From 544c83812c1697db5257fbe40ff2598ac9cf923c Mon Sep 17 00:00:00 2001 From: Levi B Date: Tue, 24 Feb 2015 18:17:07 -0800 Subject: [PATCH] Add unit tests for WeakReferenceHelpers Doc comment cleanup on IOptimizedAuthenticatedEncryptor --- DataProtection.sln | 11 +++ .../Properties/AssemblyInfo.cs | 1 + .../IOptimizedAuthenticatedEncryptor.cs | 27 +++--- ...ft.AspNet.Cryptography.Internal.Test.kproj | 17 ++++ .../Properties/AssemblyInfo.cs | 8 ++ .../WeakReferenceHelpersTests.cs | 87 +++++++++++++++++++ .../project.json | 13 +++ 7 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj create mode 100644 test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs create mode 100644 test/Microsoft.AspNet.Cryptography.Internal.Test/project.json diff --git a/DataProtection.sln b/DataProtection.sln index 3437c905a7..5d906c25f6 100644 --- a/DataProtection.sln +++ b/DataProtection.sln @@ -21,6 +21,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cryptograp EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cryptography.KeyDerivation.Test", "test\Microsoft.AspNet.Cryptography.KeyDerivation.Test\Microsoft.AspNet.Cryptography.KeyDerivation.Test.kproj", "{42C97F52-8D56-46BD-A712-4F22BED157A7}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Cryptography.Internal.Test", "test\Microsoft.AspNet.Cryptography.Internal.Test\Microsoft.AspNet.Cryptography.Internal.Test.kproj", "{37053D5F-5B61-47CE-8B72-298CE007FFB0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -77,6 +79,14 @@ Global {42C97F52-8D56-46BD-A712-4F22BED157A7}.Release|Any CPU.Build.0 = Release|Any CPU {42C97F52-8D56-46BD-A712-4F22BED157A7}.Release|x86.ActiveCfg = Release|Any CPU {42C97F52-8D56-46BD-A712-4F22BED157A7}.Release|x86.Build.0 = Release|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|x86.ActiveCfg = Debug|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Debug|x86.Build.0 = Debug|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|Any CPU.Build.0 = Release|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|x86.ActiveCfg = Release|Any CPU + {37053D5F-5B61-47CE-8B72-298CE007FFB0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -89,5 +99,6 @@ Global {E2779976-A28C-4365-A4BB-4AD854FAF23E} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA} {421F0383-34B1-402D-807B-A94542513ABA} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA} {42C97F52-8D56-46BD-A712-4F22BED157A7} = {60336AB3-948D-4D15-A5FB-F32A2B91E814} + {37053D5F-5B61-47CE-8B72-298CE007FFB0} = {60336AB3-948D-4D15-A5FB-F32A2B91E814} EndGlobalSection EndGlobal diff --git a/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs index 3f612d6db3..65c143563c 100644 --- a/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNet.Cryptography.Internal/Properties/AssemblyInfo.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; // we only ever p/invoke into DLLs known to be in the System32 folder [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)] +[assembly: InternalsVisibleTo("Microsoft.AspNet.Cryptography.Internal.Test")] [assembly: InternalsVisibleTo("Microsoft.AspNet.Cryptography.KeyDerivation")] [assembly: InternalsVisibleTo("Microsoft.AspNet.Cryptography.KeyDerivation.Test")] [assembly: InternalsVisibleTo("Microsoft.AspNet.Security.DataProtection")] diff --git a/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs b/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs index aa8d7c72fb..6535cb146b 100644 --- a/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs +++ b/src/Microsoft.AspNet.Security.DataProtection/AuthenticatedEncryption/IOptimizedAuthenticatedEncryptor.cs @@ -18,18 +18,25 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption /// the returned ciphertext but which will still be covered by the authentication tag. /// This input may be zero bytes in length. The same AAD must be specified in the corresponding /// call to Decrypt. - /// The number of bytes to include before the ciphertext in the return value. - /// The number of bytes to include after the ciphertext in the return value. + /// The number of bytes to pad before the ciphertext in the output. + /// The number of bytes to pad after the ciphertext in the output. /// - /// A buffer containing the ciphertext and authentication tag. - /// If a non-zero pre-buffer or post-buffer size is specified, the returned buffer will contain appropriate padding - /// on either side of the ciphertext and authentication tag. For instance, if a pre-buffer size of 4 and a post-buffer - /// size of 7 are specified, and if the ciphertext and tag are a combined 48 bytes, then the returned buffer will - /// be a total 59 bytes in length. The first four bytes will be undefined, the next 48 bytes will contain the - /// ciphertext and tag, and the last seven bytes will be undefined. The intent is that the caller can overwrite the - /// pre-buffer or post-buffer with a header or footer without needing to allocate an additional buffer object. + /// The ciphertext blob, including authentication tag. The ciphertext blob will be surrounded by + /// the number of padding bytes requested. For instance, if the given (plaintext, AAD) input results + /// in a (ciphertext, auth tag) output of 0x0102030405, and if 'preBufferSize' is 3 and + /// 'postBufferSize' is 5, then the return value will be 0xYYYYYY0102030405ZZZZZZZZZZ, where bytes + /// YY and ZZ are undefined. /// - /// All cryptography-related exceptions should be homogenized to CryptographicException. + /// + /// This method allows for a slight performance improvement over IAuthenticatedEncryptor.Encrypt + /// in the case where the caller needs to prepend or append some data to the resulting ciphertext. + /// For instance, if the caller needs to append a 32-bit header to the resulting ciphertext, then + /// he can specify 4 for 'preBufferSize' and overwrite the first 32 bits of the buffer returned + /// by this function. This saves the caller from having to allocate a new buffer to hold the final + /// transformed result. + /// + /// All cryptography-related exceptions should be homogenized to CryptographicException. + /// byte[] Encrypt(ArraySegment plaintext, ArraySegment additionalAuthenticatedData, uint preBufferSize, uint postBufferSize); } } diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj b/test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj new file mode 100644 index 0000000000..bf71fe331c --- /dev/null +++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/Microsoft.AspNet.Cryptography.Internal.Test.kproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 37053d5f-5b61-47ce-8b72-298ce007ffb0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..3f8188a594 --- /dev/null +++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.CompilerServices; + +// for unit testing +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs b/test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs new file mode 100644 index 0000000000..9b34dacd6d --- /dev/null +++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/WeakReferenceHelpersTests.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Xunit; + +namespace Microsoft.AspNet.Cryptography +{ + public class WeakReferenceHelpersTests + { + [Fact] + public void GetSharedInstance_ExistingWeakRefHasBeenGCed_CreatesNew() + { + // Arrange + WeakReference wrOriginal = new WeakReference(null); + WeakReference wr = wrOriginal; + MyDisposable newInstance = new MyDisposable(); + + // Act + var retVal = WeakReferenceHelpers.GetSharedInstance(ref wr, () => newInstance); + + // Assert + MyDisposable target; + Assert.NotNull(wr); + Assert.NotSame(wrOriginal, wr); + Assert.True(wr.TryGetTarget(out target)); + Assert.Same(newInstance, target); + Assert.Same(newInstance, retVal); + Assert.False(newInstance.HasBeenDisposed); + } + + [Fact] + public void GetSharedInstance_ExistingWeakRefIsNull_CreatesNew() + { + // Arrange + WeakReference wr = null; + MyDisposable newInstance = new MyDisposable(); + + // Act + var retVal = WeakReferenceHelpers.GetSharedInstance(ref wr, () => newInstance); + + // Assert + MyDisposable target; + Assert.NotNull(wr); + Assert.True(wr.TryGetTarget(out target)); + Assert.Same(newInstance, target); + Assert.Same(newInstance, retVal); + Assert.False(newInstance.HasBeenDisposed); + } + + [Fact] + public void GetSharedInstance_ExistingWeakRefIsNull_AnotherThreadCreatesInstanceWhileOurFactoryRuns_ReturnsExistingInstanceAndDisposesNewInstance() + { + // Arrange + WeakReference wr = null; + MyDisposable instanceThatWillBeCreatedFirst = new MyDisposable(); + MyDisposable instanceThatWillBeCreatedSecond = new MyDisposable(); + + // Act + var retVal = WeakReferenceHelpers.GetSharedInstance(ref wr, () => + { + // mimic another thread creating the instance while our factory is being invoked + WeakReferenceHelpers.GetSharedInstance(ref wr, () => instanceThatWillBeCreatedFirst); + return instanceThatWillBeCreatedSecond; + }); + + // Assert + MyDisposable target; + Assert.NotNull(wr); + Assert.True(wr.TryGetTarget(out target)); + Assert.Same(instanceThatWillBeCreatedFirst, target); + Assert.Same(instanceThatWillBeCreatedFirst, retVal); + Assert.False(instanceThatWillBeCreatedFirst.HasBeenDisposed); + Assert.True(instanceThatWillBeCreatedSecond.HasBeenDisposed); + } + + private sealed class MyDisposable : IDisposable + { + public bool HasBeenDisposed { get; private set; } + + public void Dispose() + { + HasBeenDisposed = true; + } + } + } +} diff --git a/test/Microsoft.AspNet.Cryptography.Internal.Test/project.json b/test/Microsoft.AspNet.Cryptography.Internal.Test/project.json new file mode 100644 index 0000000000..8f1a47255e --- /dev/null +++ b/test/Microsoft.AspNet.Cryptography.Internal.Test/project.json @@ -0,0 +1,13 @@ +{ + "dependencies": { + "Microsoft.AspNet.Cryptography.Internal": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "xunit.runner.kre": "1.0.0-*" + }, + "frameworks": { + "aspnet50": { } + }, + "commands": { + "test": "xunit.runner.kre" + } +}