diff --git a/Microsoft.Aspnet.SessionState.sln b/Microsoft.Aspnet.SessionState.sln index 591b2f2..012d7af 100644 --- a/Microsoft.Aspnet.SessionState.sln +++ b/Microsoft.Aspnet.SessionState.sln @@ -41,6 +41,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{3626D7CE-E docs\SqlSessionStateProviderAsync.md = docs\SqlSessionStateProviderAsync.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test", "test\Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test\Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test.csproj", "{AD91AAF5-3B57-4C8C-9A39-92FB578AF317}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -71,6 +73,10 @@ Global {7EC5863F-7FF1-41C7-A384-8FFF81531E7A}.Debug|Any CPU.Build.0 = Debug|Any CPU {7EC5863F-7FF1-41C7-A384-8FFF81531E7A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EC5863F-7FF1-41C7-A384-8FFF81531E7A}.Release|Any CPU.Build.0 = Release|Any CPU + {AD91AAF5-3B57-4C8C-9A39-92FB578AF317}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD91AAF5-3B57-4C8C-9A39-92FB578AF317}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD91AAF5-3B57-4C8C-9A39-92FB578AF317}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD91AAF5-3B57-4C8C-9A39-92FB578AF317}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -82,6 +88,7 @@ Global {CBB00B6C-8A44-43F0-BE73-0B0E8565F8A2} = {93AD624B-85A6-4EE9-B40E-42914D40C0CF} {2AF89ACA-3545-432D-8D99-C5230E8643A8} = {93AD624B-85A6-4EE9-B40E-42914D40C0CF} {7EC5863F-7FF1-41C7-A384-8FFF81531E7A} = {58E8143E-86D8-4CA3-AAC3-1CF253D91207} + {AD91AAF5-3B57-4C8C-9A39-92FB578AF317} = {93AD624B-85A6-4EE9-B40E-42914D40C0CF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4853AD21-0DCE-40D8-A3B9-19081B71C364} diff --git a/test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test.csproj b/test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test.csproj index fea4d7a..a647752 100644 --- a/test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test.csproj +++ b/test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test.csproj @@ -12,6 +12,12 @@ Microsoft.AspNet.SessionState.CosmosDBSessionStateProviderAsync.Test v4.6.2 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest ..\ true @@ -112,5 +118,6 @@ all + \ No newline at end of file diff --git a/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/InProcSessionStateStoreAsync.cs b/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/InProcSessionStateStoreAsync.cs new file mode 100644 index 0000000..d898a20 --- /dev/null +++ b/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/InProcSessionStateStoreAsync.cs @@ -0,0 +1,529 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See the License.txt file in the project root for full license information. + +namespace Microsoft.AspNet.SessionState.Tests +{ + using System; + using System.IO; + using System.Reflection; + using System.Threading; + using System.Threading.Tasks; + using System.Web; + using System.Web.SessionState; + using Moq; + using Xunit; + + public class InProcSessionStateStoreAsyncTests + { + private static FieldInfo s_storeDataStaticObjects = typeof(SessionStateStoreData).GetField("_staticObjects", BindingFlags.NonPublic | BindingFlags.Instance); + private static SessionStateStoreData CreateNewStoreData(InProcSessionStateStoreAsync provider, HttpContextBase httpContextBase = null, int timeout = 30, HttpStaticObjectsCollection staticObjects = null) + { + Assert.NotNull(provider); + var data = provider.CreateNewStoreData(httpContextBase, timeout); + + //if (staticObjects != null) + s_storeDataStaticObjects.SetValue(data, staticObjects ?? new HttpStaticObjectsCollection()); + + return data; + } + + private InProcSessionStateStoreAsync _provider; + + public InProcSessionStateStoreAsyncTests() + { + _provider = new InProcSessionStateStoreAsync(); + _provider.Initialize("InProcTest", null); + } + + [Fact] + public void Initialize_WithName_SetsName() + { + // Arrange + var provider = new InProcSessionStateStoreAsync(); + + // Act + provider.Initialize("TestName", null); + + // Assert + Assert.Equal("TestName", provider.Name); + } + + [Fact] + public void CreateNewStoreData_ReturnsValidData() + { + var timeout = 30; + var storeData = CreateNewStoreData(_provider, timeout: timeout); + + // Assert + Assert.NotNull(storeData); + Assert.NotNull(storeData.Items); + Assert.Empty(storeData.Items); + Assert.NotNull(storeData.StaticObjects); + Assert.Empty(storeData.StaticObjects); + Assert.Equal(timeout, storeData.Timeout); + } + + [Fact] + public async Task CreateUninitializedItem_CreatesItem() + { + // Arrange + string sessionId = "TestSession"; + int timeout = 30; + + // Act + await _provider.CreateUninitializedItemAsync(null, sessionId, timeout, CancellationToken.None); + + // Get the item to verify it was created + var result = await _provider.GetItemAsync(null, sessionId, CancellationToken.None); + + // Assert + Assert.NotNull(result); + Assert.Equal(SessionStateActions.InitializeItem, result.Actions); + } + + [Fact] + public async Task GetItemExclusive_LockItem_ReturnsLockedItem() + { + // Arrange + string sessionId = "TestSession"; + int timeout = 30; + + // Create new session + var storeData = CreateNewStoreData(_provider, timeout: timeout); + storeData.Items["TestKey"] = "TestValue"; + + await _provider.CreateUninitializedItemAsync(null, sessionId, timeout, CancellationToken.None); + + // Set the item + await _provider.SetAndReleaseItemExclusiveAsync( + null, + sessionId, + storeData, + 1, // lockCookie + true, // newItem + CancellationToken.None); + + // Get the item exclusively + var result = await _provider.GetItemExclusiveAsync(null, sessionId, CancellationToken.None); + Assert.NotNull(result); + Assert.NotNull(result.Item); + Assert.Equal("TestValue", result.Item.Items["TestKey"]); + Assert.False(result.Locked); + + // Try to get the item again - find it locked + var lockedResult = await _provider.GetItemExclusiveAsync(null, sessionId, CancellationToken.None); + Assert.NotNull(lockedResult); + Assert.Null(lockedResult.Item); + Assert.True(lockedResult.Locked); + } + + [Fact] + public async Task ReleaseItemExclusive_ReleasesLock() + { + // Arrange + string sessionId = "TestSession"; + int timeout = 30; + + // Create new session + var storeData = CreateNewStoreData(_provider, timeout: timeout); + + await _provider.CreateUninitializedItemAsync(null, sessionId, timeout, CancellationToken.None); + + // Set the item + await _provider.SetAndReleaseItemExclusiveAsync( + null, + sessionId, + storeData, + 1, // lockCookie + true, // newItem + CancellationToken.None); + + // Lock the item + var lockedResult = await _provider.GetItemExclusiveAsync(null, sessionId, CancellationToken.None); + + // Act - Release the lock + await _provider.ReleaseItemExclusiveAsync( + null, + sessionId, + lockedResult.LockId, + CancellationToken.None); + + // Try to get it again exclusively + var result = await _provider.GetItemExclusiveAsync(null, sessionId, CancellationToken.None); + + // Assert + Assert.NotNull(result); + Assert.NotNull(result.Item); + Assert.False(result.Locked); + } + + [Fact] + public async Task RemoveItem_RemovesSessionItem() + { + // Arrange + string sessionId = "TestSession"; + int timeout = 30; + + // Create new session + var storeData = CreateNewStoreData(_provider, timeout: timeout); + + await _provider.CreateUninitializedItemAsync(null, sessionId, timeout, CancellationToken.None); + + // Set the item + await _provider.SetAndReleaseItemExclusiveAsync( + null, + sessionId, + storeData, + 1, // lockCookie + true, // newItem + CancellationToken.None); + + // Lock the item + var lockedResult = await _provider.GetItemExclusiveAsync(null, sessionId, CancellationToken.None); + + // Act - Remove the item + await _provider.RemoveItemAsync( + null, + sessionId, + lockedResult.LockId, + storeData, + CancellationToken.None); + + // Try to get it again + var result = await _provider.GetItemAsync(null, sessionId, CancellationToken.None); + + // Assert + Assert.Null(result.Item); + } + + [Fact] + public async Task ResetItemTimeout_UpdatesExpiration() + { + // Arrange + string sessionId = "TestSession"; + int timeout = 30; + + // Create new session + var storeData = CreateNewStoreData(_provider, timeout: timeout); + + await _provider.CreateUninitializedItemAsync(null, sessionId, timeout, CancellationToken.None); + + // Set the item + await _provider.SetAndReleaseItemExclusiveAsync( + null, + sessionId, + storeData, + 1, // lockCookie + true, // newItem + CancellationToken.None); + + // Act - Reset timeout + await _provider.ResetItemTimeoutAsync(null, sessionId, CancellationToken.None); + + // Assert - Just verifying no exceptions + Assert.True(true); + } + + [Fact] + public async Task SetAndReleaseItemExclusive_UpdatesSessionData() + { + // Arrange + string sessionId = "TestSession"; + int timeout = 30; + + // Create new session + var storeData = CreateNewStoreData(_provider, timeout: timeout); + storeData.Items["TestKey"] = "TestValue"; + + await _provider.CreateUninitializedItemAsync(null, sessionId, timeout, CancellationToken.None); + + // Act - Set the item + await _provider.SetAndReleaseItemExclusiveAsync( + null, + sessionId, + storeData, + 1, // lockCookie + false, // newItem + CancellationToken.None); + + // Get the item to verify it was updated + var result = await _provider.GetItemAsync(null, sessionId, CancellationToken.None); + + // Assert + Assert.NotNull(result); + Assert.NotNull(result.Item); + Assert.Equal("TestValue", result.Item.Items["TestKey"]); + } + + [Fact] + public void SetItemExpireCallback_RegistersCallback() + { + // Arrange + bool callbackInvoked = false; + + // Act + bool result = _provider.SetItemExpireCallback((id, item) => callbackInvoked = true); + + // Assert + Assert.True(result); + Assert.False(callbackInvoked); + } + + [Fact] + public void Dispose_DoesNotThrow() + { + // Act & Assert - no exception should be thrown + _provider.Dispose(); + } + } + + public class ConcurrentNonSerializingSessionStateItemCollectionTests + { + private ConcurrentNonSerializingSessionStateItemCollection _collection; + + public ConcurrentNonSerializingSessionStateItemCollectionTests() + { + _collection = new ConcurrentNonSerializingSessionStateItemCollection(); + } + + [Fact] + public void Add_Item_SetsItemAndDirty() + { + // Arrange + string key = "TestKey"; + string value = "TestValue"; + + // Act + _collection[key] = value; + + // Assert + Assert.Equal(value, _collection[key]); + Assert.True(_collection.Dirty); + } + + [Fact] + public void Get_Item_ReturnsItem() + { + // Arrange + string key = "TestKey"; + string value = "TestValue"; + _collection[key] = value; + + // Reset dirty flag + _collection.Dirty = false; + + // Act + var result = _collection[key]; + + // Assert + Assert.Equal(value, result); + + // Accessing immutable object like string shouldn't set dirty flag + Assert.False(_collection.Dirty); + } + + [Fact] + public void Get_IndexedItem_ReturnsItem() + { + // Arrange + string key = "TestKey"; + string value = "TestValue"; + _collection[key] = value; + + // Reset dirty flag + _collection.Dirty = false; + + // Act + var result = _collection[0]; + + // Assert + Assert.Equal(value, result); + + // Accessing immutable object like string shouldn't set dirty flag + Assert.False(_collection.Dirty); + } + + [Fact] + public void Set_IndexedItem_SetsItemAndDirty() + { + // Arrange + string key = "TestKey"; + string value = "TestValue"; + _collection[key] = value; + + string newValue = "NewValue"; + + // Reset dirty flag + _collection.Dirty = false; + + // Act + _collection[0] = newValue; + + // Assert + Assert.Empty(_collection); + Assert.True(_collection.Dirty); + } + + [Fact] + public void Clear_RemovesAllItemsAndSetsDirty() + { + // Arrange + _collection["Key1"] = "Value1"; + _collection["Key2"] = "Value2"; + + // Reset dirty flag + _collection.Dirty = false; + + // Act + _collection.Clear(); + + // Assert + Assert.Empty(_collection); + Assert.True(_collection.Dirty); + } + + [Fact] + public void Remove_RemovesItemAndSetsDirty() + { + // Arrange + string key = "TestKey"; + string value = "TestValue"; + _collection[key] = value; + + // Reset dirty flag + _collection.Dirty = false; + + // Act + _collection.Remove(key); + + // Assert + Assert.Null(_collection[key]); + Assert.True(_collection.Dirty); + } + + [Fact] + public void RemoveAt_RemovesItemAndSetsDirty() + { + // Arrange + string key = "TestKey"; + string value = "TestValue"; + _collection[key] = value; + + // Reset dirty flag + _collection.Dirty = false; + + // Act + _collection.RemoveAt(0); + + // Assert + Assert.Empty(_collection); + Assert.True(_collection.Dirty); + } + + [Fact] + public void GetEnumerator_EnumeratesItems() + { + // Arrange + _collection["Key1"] = "Value1"; + _collection["Key2"] = "Value2"; + + // Act + int count = 0; + foreach (var key in _collection) + { + count++; + } + + // Assert + Assert.Equal(2, count); + } + + [Fact] + public void Keys_ReturnsCollectionKeys() + { + // Arrange + _collection["Key1"] = "Value1"; + _collection["Key2"] = "Value2"; + + // Act + var keys = _collection.Keys; + + // Assert + Assert.Equal(2, keys.Count); + } + } + + // Helper classes for testing if needed + public static class SessionStateItemCollectionExtensions + { + public static void SerializeToStream(this SessionStateItemCollection items, Stream stream) + { + BinaryWriter writer = new BinaryWriter(stream); + items.Serialize(writer); + } + + public static SessionStateItemCollection DeserializeFromStream(Stream stream) + { + BinaryReader reader = new BinaryReader(stream); + return SessionStateItemCollection.Deserialize(reader); + } + } + + public class ConcurrentSessionStateItemCollectionTests + { + private ConcurrentSessionStateItemCollection _collection; + + public ConcurrentSessionStateItemCollectionTests() + { + _collection = new ConcurrentSessionStateItemCollection(); + } + + [Fact] + public void Serialize_Deserialize_PreservesItems() + { + // Arrange + _collection["Key1"] = "Value1"; + _collection["Key2"] = DateTime.Now; + + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); + + // Act + _collection.Serialize(writer); + stream.Position = 0; + var reader = new BinaryReader(stream); + var deserialized = ConcurrentSessionStateItemCollection.Deserialize(reader); + + // Assert + Assert.Equal(2, deserialized.Count); + Assert.Equal("Value1", deserialized["Key1"]); + Assert.Equal(_collection["Key2"], deserialized["Key2"]); + Assert.False(deserialized.Dirty); + } + + [Fact] + public void PartialDeserialization_LoadsItemsOnDemand() + { + // Arrange + _collection["Key1"] = "Value1"; + _collection["Key2"] = "Value2"; + _collection["Key3"] = "Value3"; + + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); + + // Act - Serialize and deserialize + _collection.Serialize(writer); + stream.Position = 0; + var reader = new BinaryReader(stream); + var deserialized = ConcurrentSessionStateItemCollection.Deserialize(reader); + + // Only access the first item - this should deserialize just that item + var firstValue = deserialized["Key1"]; + + // Assert + Assert.Equal("Value1", firstValue); + Assert.Equal(3, deserialized.Count); + } + } +} diff --git a/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test.csproj b/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test.csproj new file mode 100644 index 0000000..d06d3f6 --- /dev/null +++ b/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test.csproj @@ -0,0 +1,122 @@ + + + + + + Debug + AnyCPU + {AD91AAF5-3B57-4C8C-9A39-92FB578AF317} + Library + Properties + Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test + Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test + v4.6.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + ..\ + true + + + ;INCLUDE_ADVANCED_TESTS + + + true + full + false + bin\Debug\ + TRACE;DEBUG;BUILD_GENERATED_VERSION$(IncludeAdvancedTests) + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE;BUILD_GENERATED_VERSION$(IncludeAdvancedTests) + prompt + 4 + + + true + + + $(RepositoryRoot)tools\35MSSharedLib1024.snk + + + true + + + + + + + + + + + + + + + + + + + + {7238f90d-3bce-4f40-a5ba-ea36ad484bd6} + Microsoft.AspNet.SessionState.SessionStateModule + + + + + + + + 4.2.1 + + + 4.7.137 + + + 2.4.2 + + + 2.4.2 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + 2.4.2 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + 2.4.5 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + 1.4.13 + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8700089 --- /dev/null +++ b/test/Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See the License.txt file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNet.SessionState.SessionStateModuleAsync.Test")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ad91aaf5-3b57-4c8c-9a39-92fb578af317")] diff --git a/test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test.csproj b/test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test.csproj index 5eac684..1eddfc6 100644 --- a/test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test.csproj +++ b/test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync.Test.csproj @@ -12,6 +12,12 @@ Microsoft.AspNet.SessionState.SqlSessionStateAsyncProvider.Test v4.6.2 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest ..\ true @@ -102,6 +108,7 @@ 1.4.13 +