From 17e8529ef94db8ac18cd2228e2e6882760fea6c9 Mon Sep 17 00:00:00 2001 From: Chris Bacon Date: Mon, 11 Sep 2017 22:52:34 +0100 Subject: [PATCH] Add auth tests under UWP --- .../Google.Apis.Auth.Tests.csproj | 33 ++++++--- .../GoogleJsonWebSignatureTests.cs | 12 ++-- .../Flows/AuthorizationCodeFlowTests.cs | 47 +++++-------- .../Flows/GoogleAuthorizationCodeFlowTests.cs | 14 +--- .../OAuth2/LimitedLocalhostHttpServerTests.cs | 4 ++ .../OAuth2/Pkcs8Tests.cs | 2 +- .../OAuth2/ServiceAccountCredentialTests.cs | 4 +- .../GoogleJsonWebSignature.cs | 2 +- ...ogle.Apis.IntegrationTests.Uwp.nuget.props | 6 +- .../Google.Apis.Tests.Uwp.csproj | 4 ++ .../Google.Apis.Tests.Uwp.nuget.props | 6 +- .../Google.Apis.Tests.Uwp/XunitProxy.cs | 70 ++++++++++--------- .../Apis/Utils/MemoryDataStoreTest.cs | 54 ++++++++++++++ .../ApplicationContextTests.cs | 4 +- .../Google.Apis.Tests.csproj | 2 +- .../Google.Apis/Util/Store/FileDataStore.cs | 5 +- .../Google.Apis/Util/Store/MemoryDataStore.cs | 70 +++++++++++++++++++ 17 files changed, 232 insertions(+), 107 deletions(-) create mode 100644 Src/Support/Google.Apis.Tests/Apis/Utils/MemoryDataStoreTest.cs create mode 100644 Src/Support/Google.Apis/Util/Store/MemoryDataStore.cs diff --git a/Src/Support/Google.Apis.Auth.Tests/Google.Apis.Auth.Tests.csproj b/Src/Support/Google.Apis.Auth.Tests/Google.Apis.Auth.Tests.csproj index d664d42626..aea9f05d34 100644 --- a/Src/Support/Google.Apis.Auth.Tests/Google.Apis.Auth.Tests.csproj +++ b/Src/Support/Google.Apis.Auth.Tests/Google.Apis.Auth.Tests.csproj @@ -1,35 +1,50 @@  - - netcoreapp1.0;net452;net46 + netcoreapp1.0;net452;net46;uap10.0 netcoreapp1.0 true true ..\..\..\google.apis.snk false + pdbonly + true - - - - - + + .NETStandard + v1.4 + UAP,Version=v10.0 + UAP + 10.0.14393.0 + 10.0.10240.0 + UAP,Version=v10.0 + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + $(DefineConstants);UAP10_0 + en-US + + + + + - - + + + + + \ No newline at end of file diff --git a/Src/Support/Google.Apis.Auth.Tests/GoogleJsonWebSignatureTests.cs b/Src/Support/Google.Apis.Auth.Tests/GoogleJsonWebSignatureTests.cs index 63e1d93416..9fd79c4965 100644 --- a/Src/Support/Google.Apis.Auth.Tests/GoogleJsonWebSignatureTests.cs +++ b/Src/Support/Google.Apis.Auth.Tests/GoogleJsonWebSignatureTests.cs @@ -158,7 +158,6 @@ public async Task Invalid_Aud() [Fact] public async Task Validate_Signature_Time() { - var clockInvalid1 = new MockClock() { UtcNow = new DateTime(2017, 5, 31, 10, 22, 0, DateTimeKind.Utc) }; var clockValid1 = new MockClock() { UtcNow = new DateTime(2017, 5, 31, 10, 24, 0, DateTimeKind.Utc) }; var clockValid2 = new MockClock() { UtcNow = new DateTime(2017, 5, 31, 11, 22, 0, DateTimeKind.Utc) }; @@ -188,14 +187,17 @@ public async Task Invalid_HostedDomain() [Fact] public async Task Validate_CertCache() { + // Reset GoogleJsonWebSignature before starting this test + GoogleJsonWebSignature._certCacheDownloadTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); + var clock1 = new MockClock() { UtcNow = new DateTime(2017, 5, 31, 11, 24, 0, DateTimeKind.Utc) }; var clock2Cached = new MockClock() { UtcNow = clock1.UtcNow + GoogleJsonWebSignature.CertCacheRefreshInterval - TimeSpan.FromSeconds(1) }; var clock3Uncached = new MockClock() { UtcNow = clock1.UtcNow + GoogleJsonWebSignature.CertCacheRefreshInterval + TimeSpan.FromSeconds(1) }; - var rsas1 = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock1, false, GoogleCertsJson); - var rsas2Cached = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock2Cached, false, GoogleCertsJson); - var rsas3Refreshed = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock3Uncached, false, GoogleCertsJson); - var rsas4Forced = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock3Uncached, true, GoogleCertsJson); + var rsas1 = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock1, false, GoogleCertsJson).ConfigureAwait(false); + var rsas2Cached = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock2Cached, false, GoogleCertsJson).ConfigureAwait(false); + var rsas3Refreshed = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock3Uncached, false, GoogleCertsJson).ConfigureAwait(false); + var rsas4Forced = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock3Uncached, true, GoogleCertsJson).ConfigureAwait(false); Assert.NotNull(rsas1); Assert.Same(rsas1, rsas2Cached); diff --git a/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs b/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs index ae0593059d..2f84fa7abf 100644 --- a/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs +++ b/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs @@ -23,7 +23,6 @@ using Google.Apis.Tests.Mocks; using Google.Apis.Util; using Google.Apis.Util.Store; -using Moq; using System; using System.Collections.Generic; using System.Linq; @@ -98,9 +97,7 @@ public void LoadTokenAsync_NoDataStore() [Fact] public void LoadTokenAsync_NullResponse() { - TaskCompletionSource tcs = new TaskCompletionSource(); - tcs.SetResult(null); - Assert.Null(SubtestLoadTokenAsync(tcs)); + Assert.Null(SubtestLoadTokenAsync(null)); } [Fact] @@ -110,21 +107,18 @@ public void LoadTokenAsync_TokenResponse() { AccessToken = "access" }; - - TaskCompletionSource tcs = new TaskCompletionSource(); - tcs.SetResult(response); - var result = SubtestLoadTokenAsync(tcs); + var result = SubtestLoadTokenAsync(response); Assert.Equal(response, result); } - private TokenResponse SubtestLoadTokenAsync(TaskCompletionSource tcs) + private TokenResponse SubtestLoadTokenAsync(TokenResponse response) { - var mock = new Mock(); - mock.Setup(ds => ds.GetAsync("user")).Returns(tcs.Task); - var flow = CreateFlow(dataStore: mock.Object); - var result = flow.LoadTokenAsync("user", CancellationToken.None).Result; - mock.Verify(ds => ds.GetAsync("user")); - return result; + var datastore = new MemoryDataStore(); + var flow0 = CreateFlow(dataStore: datastore); + Assert.Null(flow0.LoadTokenAsync("user", CancellationToken.None).Result); + datastore.StoreAsync("user", response).Wait(); + var flow1 = CreateFlow(dataStore: datastore); + return flow1.LoadTokenAsync("user", CancellationToken.None).Result; } #endregion @@ -148,7 +142,7 @@ public void TestCreateAuthorizationCodeRequest() [Fact] public void TestExchangeCodeForTokenAsync() { - var mock = new Mock(); + var datastore = new MemoryDataStore(); var handler = new FetchTokenMessageHandler(); handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRequest() { @@ -158,21 +152,18 @@ public void TestExchangeCodeForTokenAsync() }; MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler); - TaskCompletionSource tcs = new TaskCompletionSource(); - tcs.SetResult(null); - mock.Setup(ds => ds.StoreAsync("uSer", It.IsAny())).Returns(tcs.Task); - - var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[] { "a" }, dataStore: mock.Object); + var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[] { "a" }, dataStore: datastore); var response = flow.ExchangeCodeForTokenAsync("uSer", "c0de", "redIrect", CancellationToken.None).Result; SubtestTokenResponse(response); - mock.Verify(ds => ds.StoreAsync("uSer", It.IsAny())); + Assert.Single(datastore.Items); + Assert.EndsWith("uSer", datastore.Items.First().Key); } [Fact] public void TestRefreshTokenAsync() { - var mock = new Mock(); + var datastore = new MemoryDataStore(); var handler = new FetchTokenMessageHandler(); handler.RefreshTokenRequest = new RefreshTokenRequest() { @@ -181,16 +172,12 @@ public void TestRefreshTokenAsync() }; MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler); - TaskCompletionSource tcs = new TaskCompletionSource(); - tcs.SetResult(null); - mock.Setup(ds => ds.StoreAsync("uSer", It.IsAny())).Returns(tcs.Task); - - var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[] { "a" }, dataStore: mock.Object); + var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[] { "a" }, dataStore: datastore); var response = flow.RefreshTokenAsync("uSer", "REFRESH", CancellationToken.None).Result; SubtestTokenResponse(response); - - mock.Verify(ds => ds.StoreAsync("uSer", It.IsAny())); + Assert.Single(datastore.Items); + Assert.EndsWith("uSer", datastore.Items.First().Key); } #region FetchToken diff --git a/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/GoogleAuthorizationCodeFlowTests.cs b/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/GoogleAuthorizationCodeFlowTests.cs index 1a9af6d038..0999f44daf 100644 --- a/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/GoogleAuthorizationCodeFlowTests.cs +++ b/Src/Support/Google.Apis.Auth.Tests/OAuth2/Flows/GoogleAuthorizationCodeFlowTests.cs @@ -14,20 +14,10 @@ limitations under the License. */ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; - -using Moq; - +using Google.Apis.Auth.OAuth2; using Google.Apis.Auth.OAuth2.Flows; using Google.Apis.Auth.OAuth2.Requests; -using Google.Apis.Auth.OAuth2.Responses; -using Google.Apis.Http; -using Google.Apis.Util.Store; -using Google.Apis.Auth.OAuth2; +using System.Collections.Generic; using Xunit; namespace Google.Apis.Auth.Tests.OAuth2.Flows diff --git a/Src/Support/Google.Apis.Auth.Tests/OAuth2/LimitedLocalhostHttpServerTests.cs b/Src/Support/Google.Apis.Auth.Tests/OAuth2/LimitedLocalhostHttpServerTests.cs index 32a9649b61..b083347e2b 100644 --- a/Src/Support/Google.Apis.Auth.Tests/OAuth2/LimitedLocalhostHttpServerTests.cs +++ b/Src/Support/Google.Apis.Auth.Tests/OAuth2/LimitedLocalhostHttpServerTests.cs @@ -14,6 +14,8 @@ limitations under the License. */ +#if !UAP10_0 + using Google.Apis.Auth.OAuth2; using System; using System.Collections.Generic; @@ -152,3 +154,5 @@ public async Task InvalidRequestTooManyHeaders() } } + +#endif diff --git a/Src/Support/Google.Apis.Auth.Tests/OAuth2/Pkcs8Tests.cs b/Src/Support/Google.Apis.Auth.Tests/OAuth2/Pkcs8Tests.cs index 73770bb8a6..d7066faf41 100644 --- a/Src/Support/Google.Apis.Auth.Tests/OAuth2/Pkcs8Tests.cs +++ b/Src/Support/Google.Apis.Auth.Tests/OAuth2/Pkcs8Tests.cs @@ -137,7 +137,7 @@ public void RsaFuzzTest() Assert.Equal(publicKey.Modulus.ToByteArrayUnsigned(), Pkcs8.TrimLeadingZeroes(exportedParams.Modulus, false)); } } -#elif NETCOREAPP1_0 || NETCOREAPP1_1 +#elif NETCOREAPP1_0 || NETCOREAPP1_1 || UAP10_0 // RsaFuzzTest() can't run on net core. #else #error Unsupported platform. diff --git a/Src/Support/Google.Apis.Auth.Tests/OAuth2/ServiceAccountCredentialTests.cs b/Src/Support/Google.Apis.Auth.Tests/OAuth2/ServiceAccountCredentialTests.cs index 1d56faeb3a..b32432a04e 100644 --- a/Src/Support/Google.Apis.Auth.Tests/OAuth2/ServiceAccountCredentialTests.cs +++ b/Src/Support/Google.Apis.Auth.Tests/OAuth2/ServiceAccountCredentialTests.cs @@ -122,7 +122,7 @@ public void Pkcs8Decoding_FromPrivateKey() [Fact] public async Task ValidLocallySignedAccessToken_FromX509Certificate() { -#if NETCOREAPP1_0 || NETCOREAPP1_1 +#if NETCOREAPP1_0 || NETCOREAPP1_1 || UAP10_0 const string sPfx = @" MIIGMQIBAzCCBfcGCSqGSIb3DQEHAaCCBegEggXkMIIF4DCCAt8GCSqGSIb3DQEHBqCCAtAwggLM AgEAMIICxQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQImgNbotR3pnACAggAgIICmMHYqn7R @@ -192,7 +192,7 @@ public async Task ValidLocallySignedAccessToken_FromX509Certificate() privateKey.ImportParameters(rsaParameters); x509Cert.PrivateKey = privateKey; #else -#error Unsupported target +#error Unsupported platform #endif Assert.True(x509Cert.HasPrivateKey); diff --git a/Src/Support/Google.Apis.Auth/GoogleJsonWebSignature.cs b/Src/Support/Google.Apis.Auth/GoogleJsonWebSignature.cs index b138fcc3ca..cf6355d238 100644 --- a/Src/Support/Google.Apis.Auth/GoogleJsonWebSignature.cs +++ b/Src/Support/Google.Apis.Auth/GoogleJsonWebSignature.cs @@ -247,7 +247,7 @@ private static byte[] Base64UrlDecode(string base64Url) } private static SemaphoreSlim _certCacheLock = new SemaphoreSlim(1); - private static DateTime _certCacheDownloadTime; + internal static DateTime _certCacheDownloadTime; // internal for testing private static List _certCache; // internal for testing diff --git a/Src/Support/Google.Apis.IntegrationTests.Uwp/Google.Apis.IntegrationTests.Uwp.nuget.props b/Src/Support/Google.Apis.IntegrationTests.Uwp/Google.Apis.IntegrationTests.Uwp.nuget.props index 8144bb3d00..2277363b35 100644 --- a/Src/Support/Google.Apis.IntegrationTests.Uwp/Google.Apis.IntegrationTests.Uwp.nuget.props +++ b/Src/Support/Google.Apis.IntegrationTests.Uwp/Google.Apis.IntegrationTests.Uwp.nuget.props @@ -3,9 +3,9 @@ True NuGet - c:\chrisdunelm\uwp2\Src\Support\Google.Apis.IntegrationTests.Uwp\project.lock.json - c:\chrisdunelm\uwp2\Packages - c:\chrisdunelm\uwp2\Packages + C:\chrisdunelm\uwp2\Src\Support\Google.Apis.IntegrationTests.Uwp\project.lock.json + C:\chrisdunelm\uwp2\Packages + C:\chrisdunelm\uwp2\Packages ProjectJson 4.3.0 diff --git a/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.csproj b/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.csproj index e1b36ce856..72d535aea4 100644 --- a/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.csproj +++ b/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.csproj @@ -139,6 +139,10 @@ {b8d261f0-4c17-4887-bbc3-cbbfdf0d5328} Google.Apis.Tests + + {f106e24e-49f8-4d86-8cbf-9616178ca08c} + Google.Apis.Auth.Tests + {a0e0f5aa-6a5f-44a1-8dc7-0443f01c72e2} Google.Apis diff --git a/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.nuget.props b/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.nuget.props index d25c28f4e1..60a241c639 100644 --- a/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.nuget.props +++ b/Src/Support/Google.Apis.Tests.Uwp/Google.Apis.Tests.Uwp.nuget.props @@ -3,9 +3,9 @@ True NuGet - C:\chrisdunelm\uwp2\Src\Support\Google.Apis.Tests.Uwp\project.lock.json - C:\chrisdunelm\uwp2\Packages - C:\chrisdunelm\uwp2\Packages + c:\chrisdunelm\uwp2\Src\Support\Google.Apis.Tests.Uwp\project.lock.json + c:\chrisdunelm\uwp2\Packages + c:\chrisdunelm\uwp2\Packages ProjectJson 4.3.0 diff --git a/Src/Support/Google.Apis.Tests.Uwp/XunitProxy.cs b/Src/Support/Google.Apis.Tests.Uwp/XunitProxy.cs index 145722aeb2..11d4253565 100644 --- a/Src/Support/Google.Apis.Tests.Uwp/XunitProxy.cs +++ b/Src/Support/Google.Apis.Tests.Uwp/XunitProxy.cs @@ -1,8 +1,9 @@ -using Google.Apis.Tests.Apis.Logging; +using Google.Apis.Auth.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Linq; using System.Reflection; +using System.Threading.Tasks; namespace Google.Apis.Tests.Uwp { @@ -21,46 +22,47 @@ public XunitException(MethodInfo method, Exception inner) public void RunAllXunitTests() { // TODO: Theory tests - int testCount = 0; - var googleApiTests = typeof(NullLoggerTests).GetTypeInfo().Assembly.GetTypes(); - foreach (var type in googleApiTests) - { - var typeInfo = type.GetTypeInfo(); - // Only public classes - if (!typeInfo.IsPublic) - { - continue; - } - // Only classes that have a parameterless public constructor - var ctor = typeInfo.DeclaredConstructors.FirstOrDefault(x => x.IsPublic && !x.GetParameters().Any()); - if (ctor == null) + var googleApiTypes = typeof(ApplicationContextTests).GetTypeInfo().Assembly.GetTypes(); + var googleApiAuthTypes = typeof(GoogleJsonWebSignatureTests).GetTypeInfo().Assembly.GetTypes(); + var allTypes = googleApiTypes.Concat(googleApiAuthTypes); + var facts = allTypes + .Select(type => type.GetTypeInfo()) + .Where(typeInfo => typeInfo.IsPublic) + .Select(typeInfo => new { - continue; - } - var methods = type.GetTypeInfo().DeclaredMethods; - foreach (var method in typeInfo.DeclaredMethods) + typeInfo, + ctor = typeInfo.DeclaredConstructors.FirstOrDefault(x => x.IsPublic && !x.GetParameters().Any()) + }) + .Where(x => x.ctor != null) + .SelectMany(x => x.typeInfo.DeclaredMethods.Select(method => new { x.ctor, method })) + .Where(x => x.method.GetCustomAttribute()?.GetType() == typeof(Xunit.FactAttribute)) + .ToList(); + // Execute all xunit Fact tests + foreach (var fact in facts) + { + var test = fact.ctor.Invoke(new object[0]); + var method = fact.method; + // TODO: Perhaps collect all test failures, throw at end + try { - // TheoryAttribute derives from FactAttribute - var isFact = method.GetCustomAttribute()?.GetType() == typeof(Xunit.FactAttribute); - if (isFact) + var ret = method.Invoke(test, new object[0]); + if (method.ReturnType == typeof(Task)) { - testCount += 1; - var test = ctor.Invoke(new object[0]); - // TODO: Collect all test failures, throw at end - try - { - method.Invoke(test, new object[0]); - } - catch (Exception e) - { - e = (e as TargetInvocationException)?.InnerException ?? e; - throw new XunitException(method, e); - } + ((Task)ret).Wait(); } + else if (method.ReturnType != typeof(void)) + { + throw new InvalidOperationException($"Unexpected return type {method.ReturnType} in test method {method}"); + } + } + catch (Exception e) + { + e = (e as TargetInvocationException)?.InnerException ?? e; + throw new XunitException(method, e); } } // Confirm that the correct number of tests has actually run. - Assert.AreEqual(156, testCount); + Assert.AreEqual(224, facts.Count); } } } diff --git a/Src/Support/Google.Apis.Tests/Apis/Utils/MemoryDataStoreTest.cs b/Src/Support/Google.Apis.Tests/Apis/Utils/MemoryDataStoreTest.cs new file mode 100644 index 0000000000..6e28cc3117 --- /dev/null +++ b/Src/Support/Google.Apis.Tests/Apis/Utils/MemoryDataStoreTest.cs @@ -0,0 +1,54 @@ +using Google.Apis.Util.Store; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Google.Apis.Tests.Apis.Utils +{ + public class MemoryDataStoreTest + { + [Fact] + public async Task StoreAndGet() + { + var store = new MemoryDataStore(); + Assert.Equal(0, await store.GetAsync("key1")); + await store.StoreAsync("key1", 1); + Assert.Equal(1, await store.GetAsync("key1")); + } + + [Fact] + public async Task Delete() + { + var store = new MemoryDataStore(); + Assert.Equal(0, await store.GetAsync("key1")); + Assert.Equal(0, await store.GetAsync("key2")); + await store.StoreAsync("key1", 1); + await store.StoreAsync("key2", 2); + Assert.Equal(1, await store.GetAsync("key1")); + Assert.Equal(2, await store.GetAsync("key2")); + await store.DeleteAsync("key1"); + Assert.Equal(0, await store.GetAsync("key1")); + Assert.Equal(2, await store.GetAsync("key2")); + await store.DeleteAsync("key2"); + Assert.Equal(0, await store.GetAsync("key1")); + Assert.Equal(0, await store.GetAsync("key2")); + } + + [Fact] + public async Task StoreGetClear() + { + var store = new MemoryDataStore(); + Assert.Equal(0, await store.GetAsync("key1")); + Assert.Equal(0, await store.GetAsync("key2")); + await store.StoreAsync("key1", 1); + await store.StoreAsync("key2", 2); + Assert.Equal(1, await store.GetAsync("key1")); + Assert.Equal(2, await store.GetAsync("key2")); + await store.ClearAsync(); + Assert.Equal(0, await store.GetAsync("key1")); + Assert.Equal(0, await store.GetAsync("key2")); + } + } +} diff --git a/Src/Support/Google.Apis.Tests/ApplicationContextTests.cs b/Src/Support/Google.Apis.Tests/ApplicationContextTests.cs index 4249ec9743..f83d8f626b 100644 --- a/Src/Support/Google.Apis.Tests/ApplicationContextTests.cs +++ b/Src/Support/Google.Apis.Tests/ApplicationContextTests.cs @@ -76,7 +76,7 @@ public void GetLoggerDefaultTest() Assert.IsType(ApplicationContext.Logger); } - /// + /*/// /// Confirms that the RegisterLogger method will not fail when no logger was previously registered. /// [Fact(Skip = "Global registration of the mock logger causes other test failures.")] @@ -94,6 +94,6 @@ public void RegisterLoggerTest() Assert.Throws(() => ApplicationContext.RegisterLogger(new MockLogger())); ApplicationContext.Reset(); - } + }*/ } } diff --git a/Src/Support/Google.Apis.Tests/Google.Apis.Tests.csproj b/Src/Support/Google.Apis.Tests/Google.Apis.Tests.csproj index 01e66a1c06..5e12ce91b0 100644 --- a/Src/Support/Google.Apis.Tests/Google.Apis.Tests.csproj +++ b/Src/Support/Google.Apis.Tests/Google.Apis.Tests.csproj @@ -30,7 +30,7 @@ UAP,Version=v10.0 $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets $(DefineConstants);UAP10_0 - en-US + en-US diff --git a/Src/Support/Google.Apis/Util/Store/FileDataStore.cs b/Src/Support/Google.Apis/Util/Store/FileDataStore.cs index bbb638c0a7..22b83afe1a 100644 --- a/Src/Support/Google.Apis/Util/Store/FileDataStore.cs +++ b/Src/Support/Google.Apis/Util/Store/FileDataStore.cs @@ -175,10 +175,7 @@ public Task ClearAsync() /// Creates a unique stored key based on the key and the class type. /// The object key. /// The type to store or retrieve. - public static string GenerateStoredKey(string key, Type t) - { - return string.Format("{0}-{1}", t.FullName, key); - } + public static string GenerateStoredKey(string key, Type t) => MemoryDataStore.GenerateStoredKey(key, t); } } diff --git a/Src/Support/Google.Apis/Util/Store/MemoryDataStore.cs b/Src/Support/Google.Apis/Util/Store/MemoryDataStore.cs new file mode 100644 index 0000000000..8ea4f9ea3b --- /dev/null +++ b/Src/Support/Google.Apis/Util/Store/MemoryDataStore.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Google.Apis.Util.Store +{ + /// + /// An in-memory datastore, that stores items in memory only. + /// Contents do not persist across program restarts. + /// + public class MemoryDataStore : IDataStore + { + private static readonly Task s_completedTask = CompletedTask(); + + private static Task CompletedTask() + { + var tcs = new TaskCompletionSource(); + tcs.SetResult(default(T)); + return tcs.Task; + } + + internal static string GenerateStoredKey(string key, Type t) => string.Format("{0}-{1}", t.FullName, key); + + /// + /// Construct a new memory datastore, that stores items in memory only. + /// Contents do not persist across program restarts. + /// + public MemoryDataStore() + { + } + + /// + /// The live memory datastore contents. Writing/removing items from this dictionary + /// will alter the datastore contents. The returned dictionary is not thread-safe. + /// + public Dictionary Items { get; } = new Dictionary(); + + /// + public Task ClearAsync() + { + Items.Clear(); + return s_completedTask; + } + + /// + public Task DeleteAsync(string key) + { + Items.Remove(GenerateStoredKey(key, typeof(T))); + return s_completedTask; + } + + /// + public Task GetAsync(string key) + { + if (Items.TryGetValue(GenerateStoredKey(key, typeof(T)), out var value)) + { + return Task.FromResult((T)value); + } + return Task.FromResult(default(T)); + } + + /// + public Task StoreAsync(string key, T value) + { + Items[GenerateStoredKey(key, typeof(T))] = value; + return s_completedTask; + } + } +}