From 9bff462851241d4099b4c9972b30bec43709137d Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 5 Apr 2021 12:05:59 -0700 Subject: [PATCH 1/6] Integrated OneDriveDataStore --- ...CommunityToolkit.Uwp.Graph.Controls.csproj | 2 +- .../BaseRoamingSettingsDataStore.cs | 245 ++++++++++++++++++ .../RoamingSettings/OneDriveDataSource.cs | 62 +++++ .../RoamingSettings/OneDriveDataStore.cs | 143 ++++++++++ .../RoamingSettings/UserExtensionDataStore.cs | 191 +------------- UnitTests/UnitTests.UWP/UnitTests.UWP.csproj | 2 +- 6 files changed, 461 insertions(+), 184 deletions(-) create mode 100644 CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs create mode 100644 CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs create mode 100644 CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs diff --git a/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj b/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj index 4c79a34..8973033 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj +++ b/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj @@ -36,7 +36,7 @@ - + diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs new file mode 100644 index 0000000..537ff32 --- /dev/null +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs @@ -0,0 +1,245 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Toolkit.Uwp.Helpers; +using Windows.Storage; + +namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings +{ + /// + /// A base class for easily building roaming settings helper implementations. + /// + public abstract class BaseRoamingSettingsDataStore : IRoamingSettingsDataStore + { + /// + public EventHandler SyncCompleted { get; set; } + + /// + public EventHandler SyncFailed { get; set; } + + /// + public bool AutoSync { get; } + + /// + public string Id { get; } + + /// + public string UserId { get; } + + /// + public IDictionary Cache { get; private set; } + + /// + /// Gets an object serializer for converting objects in the data store. + /// + protected IObjectSerializer Serializer { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The id of the target Graph user. + /// A unique id for the data store. + /// An IObjectSerializer used for serializing objects. + /// Determines if the data store should sync for every interaction. + public BaseRoamingSettingsDataStore(string userId, string dataStoreId, IObjectSerializer objectSerializer, bool autoSync = true) + { + AutoSync = autoSync; + Id = dataStoreId; + UserId = userId; + Serializer = objectSerializer; + + Cache = null; + } + + /// + /// Create a new instance of the data storage container. + /// + /// A task. + public abstract Task Create(); + + /// + /// Delete the instance of the data storage container. + /// + /// A task. + public abstract Task Delete(); + + /// + public bool KeyExists(string key) + { + return Cache != null && Cache.ContainsKey(key); + } + + /// + public bool KeyExists(string compositeKey, string key) + { + if (KeyExists(compositeKey)) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; + if (composite != null) + { + return composite.ContainsKey(key); + } + } + + return false; + } + + /// + public T Read(string key, T @default = default) + { + if (Cache != null && Cache.TryGetValue(key, out object value)) + { + try + { + return Serializer.Deserialize((string)value); + } + catch + { + // Primitive types can't be deserialized. + return (T)Convert.ChangeType(value, typeof(T)); + } + } + + return @default; + } + + /// + public T Read(string compositeKey, string key, T @default = default) + { + if (Cache != null) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; + if (composite != null) + { + object value = composite[key]; + if (value != null) + { + try + { + return Serializer.Deserialize((string)value); + } + catch + { + // Primitive types can't be deserialized. + return (T)Convert.ChangeType(value, typeof(T)); + } + } + } + } + + return @default; + } + + /// + public void Save(string key, T value) + { + InitCache(); + + // Skip serialization for primitives. + if (typeof(T) == typeof(object) || Type.GetTypeCode(typeof(T)) != TypeCode.Object) + { + // Update the cache + Cache[key] = value; + } + else + { + // Update the cache + Cache[key] = Serializer.Serialize(value); + } + + if (AutoSync) + { + // Update the remote + Task.Run(() => Sync()); + } + } + + /// + public void Save(string compositeKey, IDictionary values) + { + InitCache(); + + if (KeyExists(compositeKey)) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; + + foreach (KeyValuePair setting in values.ToList()) + { + if (composite.ContainsKey(setting.Key)) + { + composite[setting.Key] = Serializer.Serialize(setting.Value); + } + else + { + composite.Add(setting.Key, Serializer.Serialize(setting.Value)); + } + } + + // Update the cache + Cache[compositeKey] = composite; + + if (AutoSync) + { + // Update the remote + Task.Run(() => Sync()); + } + } + else + { + ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue(); + foreach (KeyValuePair setting in values.ToList()) + { + composite.Add(setting.Key, Serializer.Serialize(setting.Value)); + } + + // Update the cache + Cache[compositeKey] = composite; + + if (AutoSync) + { + // Update the remote + Task.Run(() => Sync()); + } + } + } + + /// + public abstract Task FileExistsAsync(string filePath); + + /// + public abstract Task ReadFileAsync(string filePath, T @default = default); + + /// + public abstract Task SaveFileAsync(string filePath, T value); + + /// + public abstract Task Sync(); + + /// + /// Initialize the internal cache. + /// + protected void InitCache() + { + if (Cache == null) + { + Cache = new Dictionary(); + } + } + + /// + /// Clear the internal cache. + /// + protected void ClearCache() + { + if (Cache != null) + { + Cache.Clear(); + } + } + } +} diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs new file mode 100644 index 0000000..83d8deb --- /dev/null +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs @@ -0,0 +1,62 @@ +using System.IO; +using System.Text; +using System.Threading.Tasks; +using CommunityToolkit.Net.Authentication; +using CommunityToolkit.Net.Graph.Extensions; +using Microsoft.Graph; + +namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings +{ + /// + /// Helpers for interacting with files in the special OneDrive AppRoot folder. + /// + internal static class OneDriveDataSource + { + private static GraphServiceClient Graph => ProviderManager.Instance.GlobalProvider?.Graph(); + + // Create a new file. + // This fails, because OneDrive doesn't like empty files. Use Update instead. + // public static async Task Create(string fileWithExt) + // { + // var driveItem = new DriveItem() + // { + // Name = fileWithExt, + // }; + // await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Request().CreateAsync(driveItem); + // } + + /// + /// Updates or create a new file on the remote with the provided content. + /// + /// The type of object to save. + /// A representing the asynchronous operation. + public static async Task Update(string userId, string fileWithExt, T fileContents) + { + var json = Graph.HttpProvider.Serializer.SerializeObject(fileContents); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + + return await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Content.Request().PutAsync(stream); + } + + /// + /// Get a file from the remote. + /// + /// The type of object to return. + /// A representing the asynchronous operation. + public static async Task Retrieve(string userId, string fileWithExt) + { + Stream stream = await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Content.Request().GetAsync(); + + return Graph.HttpProvider.Serializer.DeserializeObject(stream); + } + + /// + /// Delete the file from the remote. + /// + /// A representing the asynchronous operation. + public static async Task Delete(string userId, string fileWithExt) + { + await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Request().DeleteAsync(); + } + } +} diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs new file mode 100644 index 0000000..13f38f6 --- /dev/null +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Toolkit.Uwp.Helpers; +using Windows.Storage; + +namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings +{ + /// + /// A DataStore for managing roaming settings in OneDrive. + /// + public class OneDriveDataStore : BaseRoamingSettingsDataStore + { + /// + /// Retrieve an object stored in a OneDrive file. + /// + /// The type of object to retrieve. + /// The id of the target Graph user. + /// The name of the file. + /// The deserialized file contents. + public static async Task Get(string userId, string fileName) + { + return await OneDriveDataSource.Retrieve(userId, fileName); + } + + /// + /// Update the contents of a OneDrive file. + /// + /// The type of object being stored. + /// The id of the target Graph user. + /// The name of the file. + /// The object to store. + /// A task. + public static async Task Set(string userId, string fileName, T fileContents) + { + await OneDriveDataSource.Update(userId, fileName, fileContents); + } + + /// + /// Delete a file from OneDrive by name. + /// + /// The id of the target Graph user. + /// The name of the file. + /// A task. + public static async Task Delete(string userId, string fileName) + { + await OneDriveDataSource.Delete(userId, fileName); + } + + /// + /// Initializes a new instance of the class. + /// + public OneDriveDataStore(string userId, string syncDataFileName, IObjectSerializer objectSerializer, bool autoSync = true) + : base(userId, syncDataFileName, objectSerializer, autoSync) + { + } + + /// + public override Task Create() + { + InitCache(); + + return Task.CompletedTask; + } + + /// + public override async Task Delete() + { + // Clear the cache + ClearCache(); + + if (AutoSync) + { + // Delete the remote. + await Delete(UserId, Id); + } + } + + /// + public override async Task FileExistsAsync(string filePath) + { + var roamingSettings = await Get(UserId, Id); + return roamingSettings != null; + } + + /// + public override async Task ReadFileAsync(string filePath, T @default = default) + { + return await Get(UserId, filePath) ?? @default; + } + + /// + public override async Task SaveFileAsync(string filePath, T value) + { + await Set(UserId, filePath, value); + + // Can't convert DriveItem to StorageFile, so we return null instead. + return null; + } + + /// + public override async Task Sync() + { + try + { + // Get the remote + string fileName = Id; + IDictionary remoteData = await Get>(UserId, fileName); + + if (remoteData.Keys.Count > 0) + { + InitCache(); + } + + bool needsUpdate = false; + + // Update local cache with additions from remote + foreach (string key in remoteData.Keys.ToList()) + { + // Only insert new values. Existing keys should be overwritten on the remote. + if (!Cache.ContainsKey(key)) + { + Cache.Add(key, remoteData[key]); + needsUpdate = true; + } + } + + if (needsUpdate) + { + // Send updates for local values, overwriting the remote. + await Set(UserId, fileName, Cache); + } + + SyncCompleted?.Invoke(this, new EventArgs()); + } + catch + { + SyncFailed?.Invoke(this, new EventArgs()); + } + } + } +} diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs index aa3eee1..d0a01c3 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs @@ -15,7 +15,7 @@ namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings /// /// An IObjectStorageHelper implementation using open extensions on the Graph User for storing key/value pairs. /// - public class UserExtensionDataStore : IRoamingSettingsDataStore + public class UserExtensionDataStore : BaseRoamingSettingsDataStore { /// /// Retrieve the value from Graph User extensions and cast the response to the provided type. @@ -93,44 +93,19 @@ public static async Task GetExtensionForUser(string userId, string ex private static readonly IList ReservedKeys = new List { "responseHeaders", "statusCode", "@odata.context" }; - /// - public EventHandler SyncCompleted { get; set; } - - /// - public EventHandler SyncFailed { get; set; } - - /// - public bool AutoSync { get; } - - /// - public string Id { get; } - - /// - public string UserId { get; } - - /// - public IDictionary Cache { get; private set; } - - private readonly IObjectSerializer _serializer; - /// /// Initializes a new instance of the class. /// public UserExtensionDataStore(string userId, string extensionId, IObjectSerializer objectSerializer, bool autoSync = true) + : base(userId, extensionId, objectSerializer, autoSync) { - AutoSync = autoSync; - Id = extensionId; - UserId = userId; - _serializer = objectSerializer; - - Cache = null; } /// /// Creates a new roaming settings extension on the Graph User. /// /// The newly created Extension object. - public async Task Create() + public override async Task Create() { InitCache(); @@ -144,10 +119,10 @@ public async Task Create() /// Deletes the roamingSettings extension from the Graph User. /// /// A void task. - public async Task Delete() + public override async Task Delete() { // Clear the cache - Cache = null; + ClearCache(); if (AutoSync) { @@ -160,7 +135,7 @@ public async Task Delete() /// Update the remote extension to match the local cache and retrieve any new keys. Any existing remote values are replaced. /// /// The freshly synced user extension. - public async Task Sync() + public override async Task Sync() { try { @@ -208,169 +183,21 @@ public async Task Sync() } /// - public virtual bool KeyExists(string key) - { - return Cache != null && Cache.ContainsKey(key); - } - - /// - public bool KeyExists(string compositeKey, string key) - { - if (KeyExists(compositeKey)) - { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; - if (composite != null) - { - return composite.ContainsKey(key); - } - } - - return false; - } - - /// - public T Read(string key, T @default = default) - { - if (Cache != null && Cache.TryGetValue(key, out object value)) - { - try - { - return _serializer.Deserialize((string)value); - } - catch - { - // Primitive types can't be deserialized. - return (T)Convert.ChangeType(value, typeof(T)); - } - } - - return @default; - } - - /// - public T Read(string compositeKey, string key, T @default = default) - { - if (Cache != null) - { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; - if (composite != null) - { - object value = composite[key]; - if (value != null) - { - try - { - return _serializer.Deserialize((string)value); - } - catch - { - // Primitive types can't be deserialized. - return (T)Convert.ChangeType(value, typeof(T)); - } - } - } - } - - return @default; - } - - /// - public void Save(string key, T value) - { - InitCache(); - - // Skip serialization for primitives. - if (typeof(T) == typeof(object) || Type.GetTypeCode(typeof(T)) != TypeCode.Object) - { - // Update the cache - Cache[key] = value; - } - else - { - // Update the cache - Cache[key] = _serializer.Serialize(value); - } - - if (AutoSync) - { - // Update the remote - Task.Run(() => Set(UserId, Id, key, value)); - } - } - - /// - public void Save(string compositeKey, IDictionary values) - { - InitCache(); - - if (KeyExists(compositeKey)) - { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; - - foreach (KeyValuePair setting in values.ToList()) - { - if (composite.ContainsKey(setting.Key)) - { - composite[setting.Key] = _serializer.Serialize(setting.Value); - } - else - { - composite.Add(setting.Key, _serializer.Serialize(setting.Value)); - } - } - - // Update the cache - Cache[compositeKey] = composite; - - if (AutoSync) - { - // Update the remote - Task.Run(() => Set(UserId, Id, compositeKey, composite)); - } - } - else - { - ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue(); - foreach (KeyValuePair setting in values.ToList()) - { - composite.Add(setting.Key, _serializer.Serialize(setting.Value)); - } - - // Update the cache - Cache[compositeKey] = composite; - - if (AutoSync) - { - // Update the remote - Task.Run(() => Set(UserId, Id, compositeKey, composite)); - } - } - } - - /// - public Task FileExistsAsync(string filePath) + public override Task FileExistsAsync(string filePath) { throw new NotImplementedException(); } /// - public Task ReadFileAsync(string filePath, T @default = default) + public override Task ReadFileAsync(string filePath, T @default = default) { throw new NotImplementedException(); } /// - public Task SaveFileAsync(string filePath, T value) + public override Task SaveFileAsync(string filePath, T value) { throw new NotImplementedException(); } - - private void InitCache() - { - if (Cache == null) - { - Cache = new Dictionary(); - } - } } } \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index ca5b3a9..477b0f1 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -176,7 +176,7 @@ 2.1.2 - 13.0.1 + 10.0.3 From 5a69eed83bb06676cc9a56ed88a483833ec8288d Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 5 Apr 2021 12:15:30 -0700 Subject: [PATCH 2/6] Added enum value to RoamingDataStore for OneDrive, and license headers --- .../Helpers/RoamingSettings/OneDriveDataSource.cs | 6 +++++- .../Helpers/RoamingSettings/OneDriveDataStore.cs | 6 +++++- .../Helpers/RoamingSettings/RoamingSettingsHelper.cs | 9 +++++++++ .../RoamingSettings/Test_UserExtensionDataStore.cs | 6 +++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs index 83d8deb..cbf3cf9 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataSource.cs @@ -1,4 +1,8 @@ -using System.IO; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; using System.Text; using System.Threading.Tasks; using CommunityToolkit.Net.Authentication; diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs index 13f38f6..1a00a20 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/RoamingSettingsHelper.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/RoamingSettingsHelper.cs index 9831656..bf14dd4 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/RoamingSettingsHelper.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/RoamingSettingsHelper.cs @@ -21,6 +21,11 @@ public enum RoamingDataStore /// Store data using open extensions on the Graph User. /// UserExtensions, + + /// + /// Store data in a Graph User's OneDrive. + /// + OneDrive, } /// @@ -95,6 +100,10 @@ public RoamingSettingsHelper(string userId, RoamingDataStore dataStore = Roaming DataStore = new UserExtensionDataStore(userId, dataStoreName, serializer, autoSync); break; + case RoamingDataStore.OneDrive: + DataStore = new OneDriveDataStore(userId, dataStoreName, serializer, autoSync); + break; + default: throw new ArgumentOutOfRangeException(nameof(dataStore)); } diff --git a/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs b/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs index 11116df..a6ecf5e 100644 --- a/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs +++ b/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs @@ -1,4 +1,8 @@ -using CommunityToolkit.Net.Authentication; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.Net.Authentication; using CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; From b9545ea06911420c83c28f84e57958f75a551b6f Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 8 Apr 2021 17:07:42 -0700 Subject: [PATCH 3/6] Improved tests for roaming data stores --- .../BaseRoamingSettingsDataStore.cs | 9 +- .../RoamingSettings/OneDriveDataStore.cs | 2 +- .../RoamingSettings/UserExtensionDataStore.cs | 4 +- .../RoamingSettings/Test_OneDriveDataStore.cs | 181 ++++++++++++++++++ .../Test_UserExtensionDataStore.cs | 95 ++++++++- UnitTests/UnitTests.UWP/UnitTests.UWP.csproj | 1 + 6 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs index 537ff32..3b034da 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs @@ -232,14 +232,11 @@ protected void InitCache() } /// - /// Clear the internal cache. + /// Delete the internal cache. /// - protected void ClearCache() + protected void DeleteCache() { - if (Cache != null) - { - Cache.Clear(); - } + Cache = null; } } } diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs index 1a00a20..475edcd 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs @@ -72,7 +72,7 @@ public override Task Create() public override async Task Delete() { // Clear the cache - ClearCache(); + DeleteCache(); if (AutoSync) { diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs index d0a01c3..dbdb480 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs @@ -121,8 +121,8 @@ public override async Task Create() /// A void task. public override async Task Delete() { - // Clear the cache - ClearCache(); + // Delete the cache + DeleteCache(); if (AutoSync) { diff --git a/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs b/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs new file mode 100644 index 0000000..a3f44d6 --- /dev/null +++ b/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs @@ -0,0 +1,181 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.Net.Authentication; +using CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings; +using Microsoft.Toolkit.Uwp.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Threading.Tasks; + +namespace UnitTests.UWP.Helpers +{ + [TestClass] + public class Test_OneDriveDataStore + { + /// + /// Test the dafault state of a new instance of the OneDriveDataStore. + /// + [TestCategory("RoamingSettings")] + [TestMethod] + public async Task Test_MockProvider_Default() + { + var tcs = new TaskCompletionSource(); + + void test() + { + try + { + string userId = "TestUserId"; + string dataStoreId = "RoamingData.json"; + IObjectSerializer serializer = new SystemSerializer(); + + IRoamingSettingsDataStore dataStore = new OneDriveDataStore(userId, dataStoreId, serializer, false); + + // Evaluate the default state is as expected + Assert.IsFalse(dataStore.AutoSync); + Assert.IsNull(dataStore.Cache); + Assert.AreEqual(dataStoreId, dataStore.Id); + Assert.AreEqual(userId, dataStore.UserId); + + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }; + + PrepareMockProvider(test); + + await tcs.Task; + } + + /// + /// Test the dafault state of a new instance of the OneDriveDataStore. + /// + [TestCategory("RoamingSettings")] + [TestMethod] + public async Task Test_MockProvider_Sync() + { + var tcs = new TaskCompletionSource(); + + async void test() + { + try + { + string userId = "TestUserId"; + string dataStoreId = "RoamingData.json"; + IObjectSerializer serializer = new SystemSerializer(); + + IRoamingSettingsDataStore dataStore = new OneDriveDataStore(userId, dataStoreId, serializer, false); + + dataStore.SyncCompleted += (s, e) => + { + try + { + Assert.Fail("Sync should have failed because we are using the MockProvider."); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }; + + dataStore.SyncFailed = (s, e) => + { + try + { + Assert.IsNull((s as IRoamingSettingsDataStore).Cache); + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }; + + await dataStore.Sync(); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + } + + PrepareMockProvider(test); + + await tcs.Task; + } + + /// + /// Test the dafault state of a new instance of the OneDriveDataStore. + /// + [TestCategory("RoamingSettings")] + [TestMethod] + public async Task Test_MockProvider_CRUD() + { + var tcs = new TaskCompletionSource(); + + async void test() + { + try + { + string userId = "TestUserId"; + string dataStoreId = "RoamingData.json"; + IObjectSerializer serializer = new SystemSerializer(); + + IRoamingSettingsDataStore dataStore = new OneDriveDataStore(userId, dataStoreId, serializer, false); + + Assert.IsNull(dataStore.Cache); + await dataStore.Create(); + Assert.IsNotNull(dataStore.Cache); + + string key = "myKey"; + string value1 = "myFirstValue"; + string value2 = "mySecondValue"; + Assert.IsFalse(dataStore.KeyExists(key)); + + dataStore.Save(key, value1); + Assert.IsTrue(dataStore.KeyExists(key)); + Assert.AreEqual(value1, dataStore.Read(key)); + + dataStore.Save(key, value2); + Assert.AreEqual(value2, dataStore.Read(key)); + + await dataStore.Delete(); + Assert.IsNull(dataStore.Cache); + + Assert.AreEqual(default, dataStore.Read(key)); + + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }; + + PrepareMockProvider(test); + + await tcs.Task; + } + + /// + /// Create a new instance of the MockProvider and check that it has the proper default state, then execute the provided action. + /// + private void PrepareMockProvider(Action test) + { + ProviderManager.Instance.ProviderUpdated += (s, e) => + { + var providerManager = s as ProviderManager; + if (providerManager.GlobalProvider.State == ProviderState.SignedIn) + { + test.Invoke(); + } + }; + ProviderManager.Instance.GlobalProvider = new MockProvider(); + } + } +} diff --git a/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs b/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs index a6ecf5e..ef202ba 100644 --- a/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs +++ b/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs @@ -23,22 +23,54 @@ public async Task Test_MockProvider_Default() { var tcs = new TaskCompletionSource(); - Action test = async () => + void test() { try { string userId = "TestUserId"; - string dataStoreId = "TestExtensionId"; + string dataStoreId = "RoamingData.json"; IObjectSerializer serializer = new SystemSerializer(); - UserExtensionDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer); + IRoamingSettingsDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer, false); // Evaluate the default state is as expected - Assert.IsTrue(dataStore.AutoSync); + Assert.IsFalse(dataStore.AutoSync); Assert.IsNull(dataStore.Cache); Assert.AreEqual(dataStoreId, dataStore.Id); Assert.AreEqual(userId, dataStore.UserId); + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }; + + PrepareMockProvider(test); + + await tcs.Task; + } + + /// + /// Test the dafault state of a new instance of the UserExtensionDataStore. + /// + [TestCategory("RoamingSettings")] + [TestMethod] + public async Task Test_MockProvider_Sync() + { + var tcs = new TaskCompletionSource(); + + async void test() + { + try + { + string userId = "TestUserId"; + string dataStoreId = "RoamingData.json"; + IObjectSerializer serializer = new SystemSerializer(); + + IRoamingSettingsDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer, false); + dataStore.SyncCompleted += (s, e) => { try @@ -55,7 +87,7 @@ public async Task Test_MockProvider_Default() { try { - Assert.IsNull((s as UserExtensionDataStore).Cache); + Assert.IsNull((s as IRoamingSettingsDataStore).Cache); tcs.SetResult(true); } catch (Exception ex) @@ -70,6 +102,59 @@ public async Task Test_MockProvider_Default() { tcs.SetException(ex); } + } + + PrepareMockProvider(test); + + await tcs.Task; + } + + /// + /// Test the dafault state of a new instance of the UserExtensionDataStore. + /// + [TestCategory("RoamingSettings")] + [TestMethod] + public async Task Test_MockProvider_CRUD() + { + var tcs = new TaskCompletionSource(); + + async void test() + { + try + { + string userId = "TestUserId"; + string dataStoreId = "RoamingData.json"; + IObjectSerializer serializer = new SystemSerializer(); + + IRoamingSettingsDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer, false); + + Assert.IsNull(dataStore.Cache); + await dataStore.Create(); + Assert.IsNotNull(dataStore.Cache); + + string key = "myKey"; + string value1 = "myFirstValue"; + string value2 = "mySecondValue"; + Assert.IsFalse(dataStore.KeyExists(key)); + + dataStore.Save(key, value1); + Assert.IsTrue(dataStore.KeyExists(key)); + Assert.AreEqual(value1, dataStore.Read(key)); + + dataStore.Save(key, value2); + Assert.AreEqual(value2, dataStore.Read(key)); + + await dataStore.Delete(); + Assert.IsNull(dataStore.Cache); + + Assert.AreEqual(default, dataStore.Read(key)); + + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } }; PrepareMockProvider(test); diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index 477b0f1..b1972d9 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -122,6 +122,7 @@ + UnitTestApp.xaml From 23840c1cc08a9a3763d1e1c86e0ccba7b8bdfdfa Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 15 Apr 2021 13:50:44 -0700 Subject: [PATCH 4/6] Fixes to OneDriveDataStore and tests --- ...CommunityToolkit.Uwp.Graph.Controls.csproj | 1 - .../RoamingSettings/OneDriveDataStore.cs | 44 ++++--- SampleTest/SampleTest.csproj | 3 + .../RoamingSettings/Test_OneDriveDataStore.cs | 112 +++++++----------- 4 files changed, 74 insertions(+), 86 deletions(-) diff --git a/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj b/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj index 8293f16..a4a3235 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj +++ b/CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph.Controls.csproj @@ -36,7 +36,6 @@ - diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs index 475edcd..46c433e 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/OneDriveDataStore.cs @@ -74,11 +74,8 @@ public override async Task Delete() // Clear the cache DeleteCache(); - if (AutoSync) - { - // Delete the remote. - await Delete(UserId, Id); - } + // Delete the remote. + await Delete(UserId, Id); } /// @@ -110,24 +107,39 @@ public override async Task Sync() { // Get the remote string fileName = Id; - IDictionary remoteData = await Get>(UserId, fileName); - - if (remoteData.Keys.Count > 0) + IDictionary remoteData = null; + try { - InitCache(); + remoteData = await Get>(UserId, fileName); + } + catch + { + // If get fails, we know the remote store does not exist. } bool needsUpdate = false; - - // Update local cache with additions from remote - foreach (string key in remoteData.Keys.ToList()) + if (remoteData != null) { - // Only insert new values. Existing keys should be overwritten on the remote. - if (!Cache.ContainsKey(key)) + if (remoteData.Keys.Count > 0) { - Cache.Add(key, remoteData[key]); - needsUpdate = true; + InitCache(); } + + // Update local cache with additions from remote + foreach (string key in remoteData.Keys.ToList()) + { + // Only insert new values. Existing keys should be overwritten on the remote. + if (!Cache.ContainsKey(key)) + { + Cache.Add(key, remoteData[key]); + needsUpdate = true; + } + } + } + else if (Cache != null && Cache.Count > 0) + { + // The remote does not yet exist, and we have data to save. + needsUpdate = true; } if (needsUpdate) diff --git a/SampleTest/SampleTest.csproj b/SampleTest/SampleTest.csproj index 4607273..9b47d2f 100644 --- a/SampleTest/SampleTest.csproj +++ b/SampleTest/SampleTest.csproj @@ -159,6 +159,9 @@ + + 4.0.0-preview.1 + 6.2.12 diff --git a/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs b/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs index a3f44d6..0e46dc4 100644 --- a/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs +++ b/UnitTests/UnitTests.UWP/RoamingSettings/Test_OneDriveDataStore.cs @@ -3,7 +3,9 @@ // See the LICENSE file in the project root for more information. using CommunityToolkit.Net.Authentication; +using CommunityToolkit.Uwp.Authentication; using CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings; +using Microsoft.Toolkit.Uwp; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -12,14 +14,14 @@ namespace UnitTests.UWP.Helpers { [TestClass] - public class Test_OneDriveDataStore + public class Test_OneDriveDataStore : VisualUITestBase { /// /// Test the dafault state of a new instance of the OneDriveDataStore. /// [TestCategory("RoamingSettings")] [TestMethod] - public async Task Test_MockProvider_Default() + public async Task Test_Default() { var tcs = new TaskCompletionSource(); @@ -47,7 +49,7 @@ void test() } }; - PrepareMockProvider(test); + PrepareProvider(test); await tcs.Task; } @@ -57,7 +59,7 @@ void test() /// [TestCategory("RoamingSettings")] [TestMethod] - public async Task Test_MockProvider_Sync() + public async Task Test_Sync() { var tcs = new TaskCompletionSource(); @@ -71,11 +73,27 @@ async void test() IRoamingSettingsDataStore dataStore = new OneDriveDataStore(userId, dataStoreId, serializer, false); - dataStore.SyncCompleted += (s, e) => + try + { + // Attempt to delete the remote first. + await dataStore.Delete(); + } + catch + { + } + + dataStore.SyncCompleted += async (s, e) => { try { - Assert.Fail("Sync should have failed because we are using the MockProvider."); + // Create a second instance to ensure that the Cache doesn't yield a false positive. + IRoamingSettingsDataStore dataStore2 = new OneDriveDataStore(userId, dataStoreId, serializer, false); + await dataStore2.Sync(); + + var foo = dataStore.Read("foo"); + Assert.AreEqual("bar", foo); + + tcs.SetResult(true); } catch (Exception ex) { @@ -87,8 +105,7 @@ async void test() { try { - Assert.IsNull((s as IRoamingSettingsDataStore).Cache); - tcs.SetResult(true); + Assert.Fail("Sync Failed"); } catch (Exception ex) { @@ -96,6 +113,7 @@ async void test() } }; + dataStore.Save("foo", "bar"); await dataStore.Sync(); } catch (Exception ex) @@ -104,78 +122,34 @@ async void test() } } - PrepareMockProvider(test); + PrepareProvider(test); - await tcs.Task; + var result = await tcs.Task; + Assert.IsTrue(result); } /// - /// Test the dafault state of a new instance of the OneDriveDataStore. + /// Create a new instance of IProvider and check that it has the proper default state, then execute the provided action. /// - [TestCategory("RoamingSettings")] - [TestMethod] - public async Task Test_MockProvider_CRUD() + private async void PrepareProvider(Action test) { - var tcs = new TaskCompletionSource(); - - async void test() + await App.DispatcherQueue.EnqueueAsync(async () => { - try - { - string userId = "TestUserId"; - string dataStoreId = "RoamingData.json"; - IObjectSerializer serializer = new SystemSerializer(); - - IRoamingSettingsDataStore dataStore = new OneDriveDataStore(userId, dataStoreId, serializer, false); - - Assert.IsNull(dataStore.Cache); - await dataStore.Create(); - Assert.IsNotNull(dataStore.Cache); + var provider = new WindowsProvider(new string[] { "User.Read", "Files.ReadWrite" }, autoSignIn: false); - string key = "myKey"; - string value1 = "myFirstValue"; - string value2 = "mySecondValue"; - Assert.IsFalse(dataStore.KeyExists(key)); - - dataStore.Save(key, value1); - Assert.IsTrue(dataStore.KeyExists(key)); - Assert.AreEqual(value1, dataStore.Read(key)); - - dataStore.Save(key, value2); - Assert.AreEqual(value2, dataStore.Read(key)); - - await dataStore.Delete(); - Assert.IsNull(dataStore.Cache); - - Assert.AreEqual(default, dataStore.Read(key)); - - tcs.SetResult(true); - } - catch (Exception ex) + ProviderManager.Instance.ProviderUpdated += (s, e) => { - tcs.SetException(ex); - } - }; - - PrepareMockProvider(test); + var providerManager = s as ProviderManager; + if (providerManager.GlobalProvider.State == ProviderState.SignedIn) + { + test.Invoke(); + } + }; - await tcs.Task; - } + ProviderManager.Instance.GlobalProvider = provider; - /// - /// Create a new instance of the MockProvider and check that it has the proper default state, then execute the provided action. - /// - private void PrepareMockProvider(Action test) - { - ProviderManager.Instance.ProviderUpdated += (s, e) => - { - var providerManager = s as ProviderManager; - if (providerManager.GlobalProvider.State == ProviderState.SignedIn) - { - test.Invoke(); - } - }; - ProviderManager.Instance.GlobalProvider = new MockProvider(); + await provider.LoginAsync(); + }); } } } From bfb5af903517bbd6781247f6e2d51b36f1d9b769 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 15 Apr 2021 14:58:05 -0700 Subject: [PATCH 5/6] Updates to UserExtensionDataStore tests to match OneDrive tests --- .../RoamingSettings/UserExtensionDataStore.cs | 30 +++-- .../Test_UserExtensionDataStore.cs | 114 +++++++----------- 2 files changed, 63 insertions(+), 81 deletions(-) diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs index dbdb480..f39736d 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs @@ -139,9 +139,17 @@ public override async Task Sync() { try { - // Get the remote - Extension extension = await GetExtensionForUser(UserId, Id); - IDictionary remoteData = extension.AdditionalData; + IDictionary remoteData = null; + + try + { + // Get the remote + Extension extension = await GetExtensionForUser(UserId, Id); + remoteData = extension.AdditionalData; + } + catch + { + } if (Cache != null) { @@ -153,24 +161,24 @@ public override async Task Sync() continue; } - if (!remoteData.ContainsKey(key) || !EqualityComparer.Default.Equals(remoteData[key], Cache[key])) + if (remoteData == null || !remoteData.ContainsKey(key) || !EqualityComparer.Default.Equals(remoteData[key], Cache[key])) { Save(key, Cache[key]); } } } - if (remoteData.Keys.Count > 0) + if (remoteData != null) { InitCache(); - } - // Update local cache with additions from remote - foreach (string key in remoteData.Keys.ToList()) - { - if (!Cache.ContainsKey(key)) + // Update local cache with additions from remote + foreach (string key in remoteData.Keys.ToList()) { - Cache.Add(key, remoteData[key]); + if (!Cache.ContainsKey(key)) + { + Cache.Add(key, remoteData[key]); + } } } diff --git a/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs b/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs index ef202ba..c4160cb 100644 --- a/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs +++ b/UnitTests/UnitTests.UWP/RoamingSettings/Test_UserExtensionDataStore.cs @@ -3,7 +3,9 @@ // See the LICENSE file in the project root for more information. using CommunityToolkit.Net.Authentication; +using CommunityToolkit.Uwp.Authentication; using CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings; +using Microsoft.Toolkit.Uwp; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -19,7 +21,7 @@ public class Test_UserExtensionDataStore /// [TestCategory("RoamingSettings")] [TestMethod] - public async Task Test_MockProvider_Default() + public async Task Test_Default() { var tcs = new TaskCompletionSource(); @@ -28,7 +30,7 @@ void test() try { string userId = "TestUserId"; - string dataStoreId = "RoamingData.json"; + string dataStoreId = "RoamingData"; IObjectSerializer serializer = new SystemSerializer(); IRoamingSettingsDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer, false); @@ -47,7 +49,7 @@ void test() } }; - PrepareMockProvider(test); + PrepareProvider(test); await tcs.Task; } @@ -57,7 +59,7 @@ void test() /// [TestCategory("RoamingSettings")] [TestMethod] - public async Task Test_MockProvider_Sync() + public async Task Test_Sync() { var tcs = new TaskCompletionSource(); @@ -66,16 +68,32 @@ async void test() try { string userId = "TestUserId"; - string dataStoreId = "RoamingData.json"; + string dataStoreId = "RoamingData"; IObjectSerializer serializer = new SystemSerializer(); IRoamingSettingsDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer, false); - dataStore.SyncCompleted += (s, e) => + try + { + // Attempt to delete the remote first. + await dataStore.Delete(); + } + catch + { + } + + dataStore.SyncCompleted += async (s, e) => { try { - Assert.Fail("Sync should have failed because we are using the MockProvider."); + // Create a second instance to ensure that the Cache doesn't yield a false positive. + IRoamingSettingsDataStore dataStore2 = new OneDriveDataStore(userId, dataStoreId, serializer, false); + await dataStore2.Sync(); + + var foo = dataStore.Read("foo"); + Assert.AreEqual("bar", foo); + + tcs.SetResult(true); } catch (Exception ex) { @@ -87,8 +105,7 @@ async void test() { try { - Assert.IsNull((s as IRoamingSettingsDataStore).Cache); - tcs.SetResult(true); + Assert.Fail("Sync Failed"); } catch (Exception ex) { @@ -96,6 +113,7 @@ async void test() } }; + dataStore.Save("foo", "bar"); await dataStore.Sync(); } catch (Exception ex) @@ -104,78 +122,34 @@ async void test() } } - PrepareMockProvider(test); + PrepareProvider(test); - await tcs.Task; + var result = await tcs.Task; + Assert.IsTrue(result); } /// - /// Test the dafault state of a new instance of the UserExtensionDataStore. + /// Create a new instance of IProvider and check that it has the proper default state, then execute the provided action. /// - [TestCategory("RoamingSettings")] - [TestMethod] - public async Task Test_MockProvider_CRUD() + private async void PrepareProvider(Action test) { - var tcs = new TaskCompletionSource(); - - async void test() + await App.DispatcherQueue.EnqueueAsync(async () => { - try - { - string userId = "TestUserId"; - string dataStoreId = "RoamingData.json"; - IObjectSerializer serializer = new SystemSerializer(); - - IRoamingSettingsDataStore dataStore = new UserExtensionDataStore(userId, dataStoreId, serializer, false); - - Assert.IsNull(dataStore.Cache); - await dataStore.Create(); - Assert.IsNotNull(dataStore.Cache); - - string key = "myKey"; - string value1 = "myFirstValue"; - string value2 = "mySecondValue"; - Assert.IsFalse(dataStore.KeyExists(key)); + var provider = new WindowsProvider(new string[] { "User.ReadWrite" }, autoSignIn: false); - dataStore.Save(key, value1); - Assert.IsTrue(dataStore.KeyExists(key)); - Assert.AreEqual(value1, dataStore.Read(key)); - - dataStore.Save(key, value2); - Assert.AreEqual(value2, dataStore.Read(key)); - - await dataStore.Delete(); - Assert.IsNull(dataStore.Cache); - - Assert.AreEqual(default, dataStore.Read(key)); - - tcs.SetResult(true); - } - catch (Exception ex) + ProviderManager.Instance.ProviderUpdated += (s, e) => { - tcs.SetException(ex); - } - }; - - PrepareMockProvider(test); + var providerManager = s as ProviderManager; + if (providerManager.GlobalProvider.State == ProviderState.SignedIn) + { + test.Invoke(); + } + }; - await tcs.Task; - } + ProviderManager.Instance.GlobalProvider = provider; - /// - /// Create a new instance of the MockProvider and check that it has the proper default state, then execute the provided action. - /// - private void PrepareMockProvider(Action test) - { - ProviderManager.Instance.ProviderUpdated += (s, e) => - { - var providerManager = s as ProviderManager; - if (providerManager.GlobalProvider.State == ProviderState.SignedIn) - { - test.Invoke(); - } - }; - ProviderManager.Instance.GlobalProvider = new MockProvider(); + await provider.LoginAsync(); + }); } } } From 1b4ae0cb974df948587be423abc69337119c3d40 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 15 Apr 2021 15:09:53 -0700 Subject: [PATCH 6/6] Removed autosync from create/delete functions in DataStores --- .../RoamingSettings/UserExtensionDataStore.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs index f39736d..0fde3df 100644 --- a/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs +++ b/CommunityToolkit.Uwp.Graph.Controls/Helpers/RoamingSettings/UserExtensionDataStore.cs @@ -109,10 +109,7 @@ public override async Task Create() { InitCache(); - if (AutoSync) - { - await Create(UserId, Id); - } + await Create(UserId, Id); } /// @@ -124,11 +121,8 @@ public override async Task Delete() // Delete the cache DeleteCache(); - if (AutoSync) - { - // Delete the remote. - await Delete(UserId, Id); - } + // Delete the remote. + await Delete(UserId, Id); } ///