| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| namespace Apache.Ignite.AspNet.Tests |
| { |
| using System; |
| using System.Collections.Specialized; |
| using System.Configuration; |
| using System.Diagnostics; |
| using System.Linq; |
| using System.Reflection; |
| using System.Threading; |
| using System.Web; |
| using System.Web.SessionState; |
| using Apache.Ignite.Core; |
| using Apache.Ignite.Core.Common; |
| using Apache.Ignite.Core.Impl.Common; |
| using Apache.Ignite.Core.Tests; |
| using NUnit.Framework; |
| |
| /// <summary> |
| /// Tests for <see cref="IgniteSessionStateStoreProvider"/>. |
| /// </summary> |
| public class IgniteSessionStateStoreProviderTest |
| { |
| /** Grid name XML config attribute. */ |
| private const string GridNameAttr = "gridName"; |
| |
| /** Cache name XML config attribute. */ |
| private const string CacheNameAttr = "cacheName"; |
| |
| /** Section name XML config attribute. */ |
| private const string SectionNameAttr = "igniteConfigurationSectionName"; |
| |
| /** Grid name. */ |
| private const string GridName = "grid1"; |
| |
| /** Cache name. */ |
| private const string CacheName = "myCache"; |
| |
| /** Session id. */ |
| private const string Id = "1"; |
| |
| /** Test context. */ |
| private static readonly HttpContext HttpContext = |
| new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null)); |
| |
| /// <summary> |
| /// Fixture setup. |
| /// </summary> |
| [TestFixtureSetUp] |
| public void TestFixtureSetUp() |
| { |
| Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) { IgniteInstanceName = GridName }); |
| } |
| |
| /// <summary> |
| /// Fixture teardown. |
| /// </summary> |
| [TestFixtureTearDown] |
| public void TestFixtureTearDown() |
| { |
| Ignition.StopAll(true); |
| } |
| |
| /// <summary> |
| /// Test teardown. |
| /// </summary> |
| [TearDown] |
| public void TearDown() |
| { |
| // Clear all caches. |
| var ignite = Ignition.GetIgnite(GridName); |
| ignite.GetCacheNames().ToList().ForEach(x => ignite.GetCache<object, object>(x).RemoveAll()); |
| } |
| |
| /// <summary> |
| /// Test setup. |
| /// </summary> |
| [SetUp] |
| public void SetUp() |
| { |
| // Make sure caches are empty. |
| var ignite = Ignition.GetIgnite(GridName); |
| |
| foreach (var cache in ignite.GetCacheNames().Select(x => ignite.GetCache<object, object>(x))) |
| CollectionAssert.IsEmpty(cache.ToArray()); |
| } |
| |
| /// <summary> |
| /// Tests provider initialization. |
| /// </summary> |
| [Test] |
| public void TestInitialization() |
| { |
| var stateProvider = new IgniteSessionStateStoreProvider(); |
| |
| SessionStateActions actions; |
| bool locked; |
| TimeSpan lockAge; |
| object lockId; |
| |
| // Not initialized. |
| Assert.Throws<InvalidOperationException>(() => |
| stateProvider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions)); |
| |
| // Missing section. |
| var ex = Assert.Throws<IgniteException>(() => |
| stateProvider.Initialize("testName", new NameValueCollection |
| { |
| {SectionNameAttr, "missingSection"}, |
| {CacheNameAttr, CacheName} |
| })); |
| |
| Assert.IsInstanceOf<ConfigurationErrorsException>(ex.InnerException); |
| |
| // Invalid section with missing content. |
| stateProvider = new IgniteSessionStateStoreProvider(); |
| |
| ex = Assert.Throws<IgniteException>(() => |
| stateProvider.Initialize("testName", new NameValueCollection |
| { |
| {SectionNameAttr, "igniteConfigurationInvalid"}, |
| {CacheNameAttr, CacheName} |
| })); |
| |
| Assert.IsInstanceOf<ConfigurationErrorsException>(ex.InnerException); |
| |
| // Valid grid. |
| stateProvider = GetProvider(); |
| |
| CheckProvider(stateProvider); |
| |
| // Same grid once again. |
| stateProvider = GetProvider(); |
| |
| CheckProvider(stateProvider); |
| |
| // Omitted cache name results in default cache name (not null). |
| stateProvider = new IgniteSessionStateStoreProvider(); |
| |
| stateProvider.Initialize("testName", new NameValueCollection |
| { |
| {GridNameAttr, GridName} |
| }); |
| |
| var cacheNames = Ignition.GetIgnite(GridName).GetCacheNames(); |
| |
| Assert.IsFalse(cacheNames.Contains(null)); |
| Assert.IsTrue(cacheNames.Contains(IgniteSessionStateStoreProvider.DefaultCacheName)); |
| } |
| |
| /// <summary> |
| /// Tests autostart from web configuration section. |
| /// </summary> |
| [Test] |
| public void TestStartFromWebConfigSection() |
| { |
| var provider = new IgniteSessionStateStoreProvider(); |
| |
| provider.Initialize("testName3", new NameValueCollection |
| { |
| {SectionNameAttr, "igniteConfiguration3"}, |
| {CacheNameAttr, "cacheName3"} |
| }); |
| |
| CheckProvider(provider); |
| } |
| |
| /// <summary> |
| /// Tests the caching. |
| /// </summary> |
| [Test] |
| public void TestCaching() |
| { |
| bool locked; |
| TimeSpan lockAge; |
| object lockId; |
| SessionStateActions actions; |
| |
| var provider = GetProvider(); |
| |
| // Not locked, no item. |
| var res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNull(res); |
| Assert.IsNull(lockId); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| // Exclusive: not locked, no item. |
| res = provider.GetItemExclusive(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNull(res); |
| Assert.IsNull(lockId); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| // SetAndRelease with no lock. This happens with certain versions of ASP.NET. |
| var item = provider.CreateNewStoreData(HttpContext, 7); |
| // ReSharper disable once AssignNullToNotNullAttribute (lockId is not supposed to be null, but it can be). |
| provider.SetAndReleaseItemExclusive(HttpContext, Id, item, null, true); |
| |
| // Check added item. |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(res); |
| Assert.IsNull(lockId); |
| Assert.AreEqual(7, res.Timeout); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| // Remove item. |
| // ReSharper disable once AssignNullToNotNullAttribute (lockId is not supposed to be null, but it can be). |
| provider.RemoveItem(HttpContext, Id, null, null); |
| |
| // Add item. |
| provider.CreateUninitializedItem(HttpContext, Id, 7); |
| |
| // Check added item. |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(res); |
| Assert.IsNull(lockId); |
| Assert.AreEqual(7, res.Timeout); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| // Lock and update. |
| res = provider.GetItemExclusive(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(res); |
| Assert.IsNotNull(lockId); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| provider.SetAndReleaseItemExclusive(HttpContext, Id, UpdateStoreData(res), lockId, false); |
| |
| // Not locked, item present. |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| CheckStoreData(res); |
| Assert.IsNull(lockId); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| // Lock item. |
| res = provider.GetItemExclusive(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| CheckStoreData(res); |
| Assert.IsNotNull(lockId); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| // Try to get it in a different thread. |
| TaskRunner.Run(() => |
| { |
| object lockId1; // do not overwrite lockId |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId1, out actions); |
| Assert.IsNull(res); |
| Assert.IsNotNull(lockId1); |
| Assert.IsTrue(locked); |
| Assert.Greater(lockAge, TimeSpan.Zero); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| }).Wait(); |
| |
| // Try to get it in a different thread. |
| TaskRunner.Run(() => |
| { |
| object lockId1; // do not overwrite lockId |
| res = provider.GetItemExclusive(HttpContext, Id, out locked, out lockAge, out lockId1, out actions); |
| Assert.IsNull(res); |
| Assert.IsNotNull(lockId1); |
| Assert.IsTrue(locked); |
| Assert.Greater(lockAge, TimeSpan.Zero); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| }).Wait(); |
| |
| // Release item. |
| provider.ReleaseItemExclusive(HttpContext, Id, lockId); |
| |
| // Make sure it is accessible in a different thread. |
| TaskRunner.Run(() => |
| { |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(res); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| }).Wait(); |
| |
| // Remove item. |
| provider.RemoveItem(HttpContext, Id, lockId, null); |
| |
| // Check removal. |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNull(res); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| } |
| |
| /// <summary> |
| /// Tests the create new store data. |
| /// </summary> |
| [Test] |
| public void TestCreateNewStoreData() |
| { |
| var provider = GetProvider(); |
| |
| var data = provider.CreateNewStoreData(HttpContext, 56); |
| |
| Assert.AreEqual(56, data.Timeout); |
| Assert.IsEmpty(data.Items); |
| Assert.IsEmpty(data.StaticObjects); |
| |
| // Check that caches are empty. |
| var ignite = Ignition.GetIgnite(GridName); |
| Assert.IsFalse(ignite.GetCacheNames().SelectMany(x => ignite.GetCache<int, int>(x)).Any()); |
| } |
| |
| /// <summary> |
| /// Tests the expiry. |
| /// </summary> |
| [Test] |
| [Category(TestUtils.CategoryIntensive)] // Minimum expiration is 1 minute |
| public void TestExpiry() |
| { |
| var provider = GetProvider(); |
| |
| bool locked; |
| TimeSpan lockAge; |
| object lockId; |
| SessionStateActions actions; |
| |
| // Callbacks are not supported for now. |
| Assert.IsFalse(GetProvider().SetItemExpireCallback(null)); |
| |
| // Check there is no item. |
| var res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNull(res); |
| |
| // Put an item with CreateUninitializedItem and check. |
| provider.CreateUninitializedItem(HttpContext, Id, 1); |
| CheckExpiry(provider); |
| |
| // Put an item with SetAndReleaseItemExclusive and check. |
| var data = provider.CreateNewStoreData(HttpContext, 1); |
| provider.SetAndReleaseItemExclusive(HttpContext, Id, data, lockId, true); |
| CheckExpiry(provider); |
| } |
| |
| /// <summary> |
| /// Checks item expiration. |
| /// </summary> |
| private static void CheckExpiry(SessionStateStoreProviderBase provider) |
| { |
| bool locked; |
| TimeSpan lockAge; |
| object lockId; |
| SessionStateActions actions; |
| |
| // Check that item is present. |
| var res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(res); |
| |
| // Wait a minute and check again. |
| Thread.Sleep(TimeSpan.FromMinutes(1.05)); |
| |
| res = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNull(res); |
| } |
| |
| /// <summary> |
| /// Tests the create uninitialized item. |
| /// </summary> |
| [Test] |
| public void TestCreateUninitializedItem() |
| { |
| bool locked; |
| TimeSpan lockAge; |
| object lockId; |
| SessionStateActions actions; |
| |
| var provider = GetProvider(); |
| provider.CreateUninitializedItem(HttpContext, "myId", 45); |
| |
| var res = provider.GetItem(HttpContext, "myId", out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(res); |
| Assert.AreEqual(45, res.Timeout); |
| Assert.AreEqual(0, res.Items.Count); |
| Assert.AreEqual(0, res.StaticObjects.Count); |
| } |
| |
| /// <summary> |
| /// Updates the store data. |
| /// </summary> |
| private static SessionStateStoreData UpdateStoreData(SessionStateStoreData data) |
| { |
| data.Timeout = 8; |
| |
| data.Items["name1"] = 1; |
| data.Items["name2"] = "2"; |
| |
| var statics = data.StaticObjects; |
| |
| // Modification method is internal. |
| var method = statics.GetType() |
| .GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic); |
| |
| Debug.Assert(method != null); |
| |
| method.Invoke(statics, new object[] {"int", typeof(int), false}); |
| |
| CheckStoreData(data); |
| |
| return data; |
| } |
| |
| /// <summary> |
| /// Checks that store data is the same as <see cref="UpdateStoreData"/> returns. |
| /// </summary> |
| private static void CheckStoreData(SessionStateStoreData data) |
| { |
| Assert.IsNotNull(data); |
| |
| Assert.AreEqual(8, data.Timeout); |
| |
| Assert.AreEqual(1, data.Items["name1"]); |
| Assert.AreEqual(1, data.Items[0]); |
| |
| Assert.AreEqual("2", data.Items["name2"]); |
| Assert.AreEqual("2", data.Items[1]); |
| |
| Assert.AreEqual(0, data.StaticObjects["int"]); |
| } |
| |
| /// <summary> |
| /// Gets the initialized provider. |
| /// </summary> |
| private static IgniteSessionStateStoreProvider GetProvider() |
| { |
| var stateProvider = new IgniteSessionStateStoreProvider(); |
| |
| stateProvider.Initialize("testName", new NameValueCollection |
| { |
| {GridNameAttr, GridName}, |
| {CacheNameAttr, CacheName} |
| }); |
| |
| return stateProvider; |
| } |
| |
| /// <summary> |
| /// Checks the provider. |
| /// </summary> |
| private static void CheckProvider(SessionStateStoreProviderBase provider) |
| { |
| bool locked; |
| TimeSpan lockAge; |
| object lockId; |
| SessionStateActions actions; |
| |
| provider.InitializeRequest(HttpContext); |
| provider.CreateUninitializedItem(HttpContext, Id, 42); |
| |
| var data = provider.GetItem(HttpContext, Id, out locked, out lockAge, out lockId, out actions); |
| Assert.IsNotNull(data); |
| Assert.AreEqual(42, data.Timeout); |
| Assert.IsFalse(locked); |
| Assert.AreEqual(TimeSpan.Zero, lockAge); |
| Assert.IsNull(lockId); |
| Assert.AreEqual(SessionStateActions.None, actions); |
| |
| provider.ResetItemTimeout(HttpContext, Id); |
| provider.EndRequest(HttpContext); |
| provider.Dispose(); |
| } |
| } |
| } |