1 // 2 // MemoryCacheTest.cs 3 // 4 // Authors: 5 // Marek Habersack <mhabersack@novell.com> 6 // 7 // Copyright (C) 2010 Novell, Inc. (http://novell.com/) 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 using System; 29 using System.Collections; 30 using System.Collections.Generic; 31 using System.Collections.ObjectModel; 32 using System.Collections.Specialized; 33 using System.Runtime.Caching; 34 using System.Threading; 35 36 using NUnit.Framework; 37 using MonoTests.Common; 38 39 namespace MonoTests.System.Runtime.Caching 40 { 41 [TestFixture] 42 public class MemoryCacheTest 43 { 44 [Test] ConstructorParameters()45 public void ConstructorParameters () 46 { 47 MemoryCache mc; 48 Assert.Throws<ArgumentNullException> (() => { 49 mc = new MemoryCache (null); 50 }, "#A1"); 51 52 Assert.Throws<ArgumentException> (() => { 53 mc = new MemoryCache (String.Empty); 54 }, "#A2"); 55 56 Assert.Throws<ArgumentException> (() => { 57 mc = new MemoryCache ("default"); 58 }, "#A3"); 59 60 var config = new NameValueCollection (); 61 config.Add ("CacheMemoryLimitMegabytes", "invalid"); 62 Assert.Throws<ArgumentException> (() => { 63 mc = new MemoryCache ("MyCache", config); 64 }, "#A4-1"); 65 66 config.Clear (); 67 config.Add ("PhysicalMemoryLimitPercentage", "invalid"); 68 Assert.Throws<ArgumentException> (() => { 69 mc = new MemoryCache ("MyCache", config); 70 }, "#A4-2"); 71 72 config.Clear (); 73 config.Add ("PollingInterval", "invalid"); 74 Assert.Throws<ArgumentException> (() => { 75 mc = new MemoryCache ("MyCache", config); 76 }, "#A4-3"); 77 78 config.Clear (); 79 config.Add ("CacheMemoryLimitMegabytes", "-1"); 80 Assert.Throws<ArgumentException> (() => { 81 mc = new MemoryCache ("MyCache", config); 82 }, "#A4-4"); 83 84 config.Clear (); 85 config.Add ("CacheMemoryLimitMegabytes", UInt64.MaxValue.ToString ()); 86 Assert.Throws<ArgumentException> (() => { 87 mc = new MemoryCache ("MyCache", config); 88 }, "#A4-5"); 89 90 config.Clear (); 91 config.Add ("PhysicalMemoryLimitPercentage", "-1"); 92 Assert.Throws<ArgumentException> (() => { 93 mc = new MemoryCache ("MyCache", config); 94 }, "#A4-6"); 95 96 config.Clear (); 97 config.Add ("PhysicalMemoryLimitPercentage", UInt64.MaxValue.ToString ()); 98 Assert.Throws<ArgumentException> (() => { 99 mc = new MemoryCache ("MyCache", config); 100 }, "#A4-7"); 101 102 config.Clear (); 103 config.Add ("PhysicalMemoryLimitPercentage", UInt32.MaxValue.ToString ()); 104 Assert.Throws<ArgumentException> (() => { 105 mc = new MemoryCache ("MyCache", config); 106 }, "#A4-8"); 107 108 config.Clear (); 109 config.Add ("PhysicalMemoryLimitPercentage", "-10"); 110 Assert.Throws<ArgumentException> (() => { 111 mc = new MemoryCache ("MyCache", config); 112 }, "#A4-9"); 113 114 config.Clear (); 115 config.Add ("PhysicalMemoryLimitPercentage", "0"); 116 // Just make sure it doesn't throw any exception 117 mc = new MemoryCache ("MyCache", config); 118 119 config.Clear (); 120 config.Add ("PhysicalMemoryLimitPercentage", "101"); 121 Assert.Throws<ArgumentException> (() => { 122 mc = new MemoryCache ("MyCache", config); 123 }, "#A4-10"); 124 125 // Just make sure it doesn't throw any exception 126 config.Clear (); 127 config.Add ("UnsupportedSetting", "123"); 128 mc = new MemoryCache ("MyCache", config); 129 } 130 131 [Test] Defaults()132 public void Defaults () 133 { 134 var mc = new MemoryCache ("MyCache"); 135 Assert.AreEqual ("MyCache", mc.Name, "#A1"); 136 // Value of this property is different from system to system 137 //Assert.AreEqual (0, mc.CacheMemoryLimit, "#A3"); 138 Assert.AreEqual (TimeSpan.FromMinutes (2), mc.PollingInterval, "#A4"); 139 Assert.AreEqual ( 140 DefaultCacheCapabilities.InMemoryProvider | 141 DefaultCacheCapabilities.CacheEntryChangeMonitors | 142 DefaultCacheCapabilities.AbsoluteExpirations | 143 DefaultCacheCapabilities.SlidingExpirations | 144 DefaultCacheCapabilities.CacheEntryRemovedCallback | 145 DefaultCacheCapabilities.CacheEntryUpdateCallback, 146 mc.DefaultCacheCapabilities, "#A1"); 147 } 148 149 [Test] DefaultInstanceDefaults()150 public void DefaultInstanceDefaults () 151 { 152 var mc = MemoryCache.Default; 153 Assert.AreEqual ("Default", mc.Name, "#A1"); 154 // Value of this property is different from system to system 155 //Assert.AreEqual (0, mc.CacheMemoryLimit, "#A3"); 156 Assert.AreEqual (TimeSpan.FromMinutes (2), mc.PollingInterval, "#A4"); 157 Assert.AreEqual ( 158 DefaultCacheCapabilities.InMemoryProvider | 159 DefaultCacheCapabilities.CacheEntryChangeMonitors | 160 DefaultCacheCapabilities.AbsoluteExpirations | 161 DefaultCacheCapabilities.SlidingExpirations | 162 DefaultCacheCapabilities.CacheEntryRemovedCallback | 163 DefaultCacheCapabilities.CacheEntryUpdateCallback, 164 mc.DefaultCacheCapabilities, "#A1"); 165 } 166 167 [Test] ConstructorValues()168 public void ConstructorValues () 169 { 170 var config = new NameValueCollection (); 171 config.Add ("CacheMemoryLimitMegabytes", "1"); 172 config.Add ("pollingInterval", "00:10:00"); 173 174 var mc = new MemoryCache ("MyCache", config); 175 Assert.AreEqual (1048576, mc.CacheMemoryLimit, "#A2"); 176 Assert.AreEqual (TimeSpan.FromMinutes (10), mc.PollingInterval, "#A3"); 177 178 config.Clear (); 179 config.Add ("PhysicalMemoryLimitPercentage", "10"); 180 config.Add ("CacheMemoryLimitMegabytes", "5"); 181 config.Add ("PollingInterval", "01:10:00"); 182 183 mc = new MemoryCache ("MyCache", config); 184 Assert.AreEqual (10, mc.PhysicalMemoryLimit, "#B1"); 185 Assert.AreEqual (5242880, mc.CacheMemoryLimit, "#B2"); 186 Assert.AreEqual (TimeSpan.FromMinutes (70), mc.PollingInterval, "#B3"); 187 } 188 189 [Test] Indexer()190 public void Indexer () 191 { 192 var mc = new PokerMemoryCache ("MyCache"); 193 194 Assert.Throws<ArgumentNullException> (() => { 195 mc [null] = "value"; 196 }, "#A1-1"); 197 198 Assert.Throws<ArgumentNullException> (() => { 199 object v = mc [null]; 200 }, "#A1-2"); 201 202 Assert.Throws<ArgumentNullException> (() => { 203 mc ["key"] = null; 204 }, "#A1-3"); 205 206 mc.Calls.Clear (); 207 mc ["key"] = "value"; 208 Assert.AreEqual (3, mc.Calls.Count, "#A2-1"); 209 Assert.AreEqual ("set_this [string key]", mc.Calls [0], "#A2-2"); 210 Assert.AreEqual ("Set (string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)", mc.Calls [1], "#A2-3"); 211 Assert.AreEqual ("Set (string key, object value, CacheItemPolicy policy, string regionName = null)", mc.Calls [2], "#A2-4"); 212 Assert.IsTrue (mc.Contains ("key"), "#A2-5"); 213 214 mc.Calls.Clear (); 215 object value = mc ["key"]; 216 Assert.AreEqual (1, mc.Calls.Count, "#A3-1"); 217 Assert.AreEqual ("get_this [string key]", mc.Calls [0], "#A3-2"); 218 Assert.AreEqual ("value", value, "#A3-3"); 219 } 220 221 [Test] Contains()222 public void Contains () 223 { 224 var mc = new PokerMemoryCache ("MyCache"); 225 226 Assert.Throws<ArgumentNullException> (() => { 227 mc.Contains (null); 228 }, "#A1-1"); 229 230 Assert.Throws<NotSupportedException> (() => { 231 mc.Contains ("key", "region"); 232 }, "#A1-2"); 233 234 mc.Set ("key", "value", ObjectCache.InfiniteAbsoluteExpiration); 235 Assert.IsTrue (mc.Contains ("key"), "#A2"); 236 237 var cip = new CacheItemPolicy (); 238 cip.Priority = CacheItemPriority.NotRemovable; 239 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (500); 240 mc.Set ("key", "value", cip); 241 Assert.IsTrue (mc.Contains ("key"), "#B1-1"); 242 Thread.Sleep (1000); 243 // The call below removes the expired entry and returns false 244 Assert.IsFalse (mc.Contains ("key"), "#B1-2"); 245 } 246 247 [Test] CreateCacheEntryChangeMonitor()248 public void CreateCacheEntryChangeMonitor () 249 { 250 var mc = new PokerMemoryCache ("MyCache"); 251 252 Assert.Throws<NotSupportedException> (() => { 253 mc.CreateCacheEntryChangeMonitor (new string [] { "key" }, "region"); 254 }, "#A1-1"); 255 256 Assert.Throws<ArgumentNullException> (() => { 257 mc.CreateCacheEntryChangeMonitor (null); 258 }, "#A1-2"); 259 260 Assert.Throws<ArgumentException> (() => { 261 mc.CreateCacheEntryChangeMonitor (new string [] {}); 262 }, "#A1-3"); 263 264 Assert.Throws<ArgumentException> (() => { 265 mc.CreateCacheEntryChangeMonitor (new string [] { "key", null }); 266 }, "#A1-4"); 267 268 mc.Set ("key1", "value1", ObjectCache.InfiniteAbsoluteExpiration); 269 mc.Set ("key2", "value2", ObjectCache.InfiniteAbsoluteExpiration); 270 mc.Set ("key3", "value3", ObjectCache.InfiniteAbsoluteExpiration); 271 272 CacheEntryChangeMonitor monitor = mc.CreateCacheEntryChangeMonitor (new string [] { "key1", "key2" }); 273 Assert.IsNotNull (monitor, "#A2-1"); 274 Assert.AreEqual ("System.Runtime.Caching.MemoryCacheEntryChangeMonitor", monitor.GetType ().ToString (), "#A2-2"); 275 Assert.AreEqual (2, monitor.CacheKeys.Count, "#A2-3"); 276 Assert.AreEqual ("key1", monitor.CacheKeys [0], "#A2-3-1"); 277 Assert.AreEqual ("key2", monitor.CacheKeys [1], "#A2-3-2"); 278 Assert.IsNull (monitor.RegionName, "#A2-4"); 279 // Since this comparison can fail from time to time, leaving it commented out 280 //Assert.AreEqual (DateTimeOffset.UtcNow.ToString (), monitor.LastModified.ToString (), "#A2-5"); 281 Assert.IsFalse (monitor.HasChanged, "#A2-5"); 282 283 // The actual unique id is constructed from key names followed by the hex value of ticks of their last modifed time 284 Assert.IsFalse (String.IsNullOrEmpty (monitor.UniqueId), "#A2-6"); 285 286 // There seems to be a bug in .NET 4.0 regarding the code below. MSDN says that non-existing keys will cause the 287 // returned monitor instance to be marked as changed, but instead this exception is thrown: 288 // 289 // MonoTests.System.Runtime.Caching.MemoryCacheTest.CreateCacheEntryChangeMonitor: 290 // System.ArgumentOutOfRangeException : The UTC time represented when the offset is applied must be between year 0 and 10,000. 291 // Parameter name: offset 292 // 293 // at System.DateTimeOffset.ValidateDate(DateTime dateTime, TimeSpan offset) 294 // at System.DateTimeOffset..ctor(DateTime dateTime) 295 // at System.Runtime.Caching.MemoryCacheEntryChangeMonitor.InitDisposableMembers(MemoryCache cache) 296 // at System.Runtime.Caching.MemoryCache.CreateCacheEntryChangeMonitor(IEnumerable`1 keys, String regionName) 297 // at MonoTests.Common.PokerMemoryCache.CreateCacheEntryChangeMonitor(IEnumerable`1 keys, String regionName) in C:\Users\grendel\documents\visual studio 2010\Projects\System.Runtime.Caching.Test\System.Runtime.Caching.Test\Common\PokerMemoryCache.cs:line 113 298 // at MonoTests.System.Runtime.Caching.MemoryCacheTest.CreateCacheEntryChangeMonitor() in C:\Users\grendel\documents\visual studio 2010\Projects\System.Runtime.Caching.Test\System.Runtime.Caching.Test\System.Runtime.Caching\MemoryCacheTest.cs:line 275 299 // 300 // It's probably caused by the code passing a DateTime.MinValue to DateTimeOffset constructor for non-existing entries. 301 // Until this (apparent) bug is fixed, Mono is going to implement the buggy behavior. 302 // 303 #if false 304 monitor = mc.CreateCacheEntryChangeMonitor (new string [] { "key1", "doesnotexist" }); 305 Assert.IsNotNull (monitor, "#A3-1"); 306 Assert.AreEqual ("System.Runtime.Caching.MemoryCacheEntryChangeMonitor", monitor.GetType ().ToString (), "#A3-2"); 307 Assert.AreEqual (1, monitor.CacheKeys.Count, "#A3-3"); 308 Assert.AreEqual ("key1", monitor.CacheKeys [0], "#A3-3-1"); 309 Assert.IsNull (monitor.RegionName, "#A3-4"); 310 Assert.IsTrue (monitor.HasChanged, "#A3-5"); 311 #endif 312 } 313 314 [Test] AddOrGetExisting_String_Object_DateTimeOffset_String()315 public void AddOrGetExisting_String_Object_DateTimeOffset_String () 316 { 317 var mc = new PokerMemoryCache ("MyCache"); 318 319 Assert.Throws<ArgumentNullException> (() => { 320 mc.AddOrGetExisting (null, "value", DateTimeOffset.Now); 321 }, "#A1-1"); 322 323 Assert.Throws<ArgumentNullException> (() => { 324 mc.AddOrGetExisting ("key", null, DateTimeOffset.Now); 325 }, "#A1-2"); 326 327 Assert.Throws<NotSupportedException> (() => { 328 mc.AddOrGetExisting ("key", "value", DateTimeOffset.Now, "region"); 329 }, "#A1-3"); 330 331 object value = mc.AddOrGetExisting ("key3_A2-1", "value", DateTimeOffset.Now.AddMinutes (1)); 332 Assert.IsTrue (mc.Contains ("key3_A2-1"), "#A2-1"); 333 Assert.IsNull (value, "#A2-2"); 334 335 mc.Calls.Clear (); 336 value = mc.AddOrGetExisting ("key3_A2-1", "value2", DateTimeOffset.Now.AddMinutes (1)); 337 Assert.IsTrue (mc.Contains ("key3_A2-1"), "#A3-1"); 338 Assert.IsNotNull (value, "#A3-2"); 339 Assert.AreEqual ("value", value, "#A3-3"); 340 Assert.AreEqual (2, mc.Calls.Count, "#A3-4"); 341 Assert.AreEqual ("AddOrGetExisting (string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)", mc.Calls [0], "#A3-5"); 342 343 value = mc.AddOrGetExisting ("key_expired", "value", DateTimeOffset.MinValue); 344 Assert.IsFalse (mc.Contains ("key_expired"), "#A4-1"); 345 Assert.IsNull (value, "#A4-1"); 346 } 347 348 [Test] AddOrGetExisting_String_Object_CacheItemPolicy_String()349 public void AddOrGetExisting_String_Object_CacheItemPolicy_String () 350 { 351 var mc = new PokerMemoryCache ("MyCache"); 352 353 Assert.Throws<ArgumentNullException> (() => { 354 mc.AddOrGetExisting (null, "value", null); 355 }, "#A1-1"); 356 357 Assert.Throws<ArgumentNullException> (() => { 358 mc.AddOrGetExisting ("key", null, null); 359 }, "#A1-2"); 360 361 var cip = new CacheItemPolicy (); 362 cip.AbsoluteExpiration = DateTime.Now.AddMinutes (1); 363 cip.SlidingExpiration = TimeSpan.FromMinutes (1); 364 365 Assert.Throws<ArgumentException> (() => { 366 mc.AddOrGetExisting ("key", "value", cip); 367 }, "#A1-3"); 368 369 cip = new CacheItemPolicy (); 370 cip.SlidingExpiration = TimeSpan.MinValue; 371 Assert.Throws<ArgumentOutOfRangeException> (() => { 372 mc.AddOrGetExisting ("key3", "value", cip); 373 }, "#A1-4"); 374 375 Assert.Throws<NotSupportedException> (() => { 376 mc.AddOrGetExisting ("key", "value", null, "region"); 377 }, "#A1-5"); 378 379 cip = new CacheItemPolicy (); 380 cip.SlidingExpiration = TimeSpan.FromDays (500); 381 Assert.Throws<ArgumentOutOfRangeException> (() => { 382 mc.AddOrGetExisting ("key3", "value", cip); 383 }, "#A1-6"); 384 385 cip = new CacheItemPolicy (); 386 cip.Priority = (CacheItemPriority) 20; 387 Assert.Throws<ArgumentOutOfRangeException> (() => { 388 mc.AddOrGetExisting ("key3", "value", cip); 389 }, "#A1-7"); 390 391 cip = new CacheItemPolicy (); 392 cip.SlidingExpiration = TimeSpan.FromTicks (0L); 393 mc.AddOrGetExisting ("key3_A2-1", "value", cip); 394 Assert.IsTrue (mc.Contains ("key3_A2-1"), "#A2-1"); 395 396 cip = new CacheItemPolicy (); 397 cip.SlidingExpiration = TimeSpan.FromDays (365); 398 mc.AddOrGetExisting ("key3_A2-2", "value", cip); 399 Assert.IsTrue (mc.Contains ("key3_A2-2"), "#A2-2"); 400 401 cip = new CacheItemPolicy (); 402 cip.RemovedCallback = (CacheEntryRemovedArguments arguments) => { }; 403 object value = mc.AddOrGetExisting ("key3_A2-3", "value", cip); 404 Assert.IsTrue (mc.Contains ("key3_A2-3"), "#A2-3"); 405 Assert.IsNull (value, "#A2-4"); 406 407 mc.Calls.Clear (); 408 value = mc.AddOrGetExisting ("key3_A2-3", "value2", null); 409 Assert.IsTrue (mc.Contains ("key3_A2-3"), "#A3-1"); 410 Assert.IsNotNull (value, "#A3-2"); 411 Assert.AreEqual ("value", value, "#A3-3"); 412 Assert.AreEqual (2, mc.Calls.Count, "#A3-4"); 413 Assert.AreEqual ("AddOrGetExisting (string key, object value, CacheItemPolicy policy, string regionName = null)", mc.Calls [0], "#A3-5"); 414 415 cip = new CacheItemPolicy (); 416 cip.AbsoluteExpiration = DateTimeOffset.MinValue; 417 value = mc.AddOrGetExisting ("key_expired", "value", cip); 418 Assert.IsFalse (mc.Contains ("key_expired"), "#A4-1"); 419 Assert.IsNull (value, "#A4-1"); 420 } 421 422 [Test] AddOrGetExisting_CacheItem_CacheItemPolicy()423 public void AddOrGetExisting_CacheItem_CacheItemPolicy () 424 { 425 var mc = new PokerMemoryCache ("MyCache"); 426 CacheItem ci, ci2; 427 428 Assert.Throws<ArgumentNullException> (() => { 429 ci = mc.AddOrGetExisting (null, new CacheItemPolicy ()); 430 }, "#A1"); 431 432 ci = new CacheItem ("key", "value"); 433 ci2 = mc.AddOrGetExisting (ci, null); 434 435 // LAMESPEC: MSDN says it should return null if the entry does not exist yet. 436 // 437 Assert.IsNotNull (ci2, "#A2-1"); 438 Assert.AreNotEqual (ci, ci2, "#A2-2"); 439 Assert.IsNull (ci2.Value, "#A2-3"); 440 Assert.IsTrue (mc.Contains (ci.Key), "#A2-4"); 441 Assert.AreEqual (ci.Key, ci2.Key, "#A2-5"); 442 443 ci = new CacheItem ("key", "value"); 444 ci2 = mc.AddOrGetExisting (ci, null); 445 Assert.IsNotNull (ci2, "#A3-1"); 446 Assert.AreNotEqual (ci, ci2, "#A3-2"); 447 Assert.IsNotNull (ci2.Value, "#A3-3"); 448 Assert.AreEqual (ci.Value, ci2.Value, "#A3-4"); 449 Assert.AreEqual (ci.Key, ci2.Key, "#A3-5"); 450 451 Assert.Throws<ArgumentNullException> (() => { 452 ci = new CacheItem (null, "value"); 453 ci2 = mc.AddOrGetExisting (ci, null); 454 }, "#A4"); 455 456 ci = new CacheItem (String.Empty, "value"); 457 ci2 = mc.AddOrGetExisting (ci, null); 458 Assert.IsNotNull (ci2, "#A5-1"); 459 Assert.AreNotEqual (ci, ci2, "#A5-2"); 460 Assert.IsNull (ci2.Value, "#A5-3"); 461 Assert.IsTrue (mc.Contains (ci.Key), "#A5-4"); 462 Assert.AreEqual (ci.Key, ci2.Key, "#A5-5"); 463 464 ci = new CacheItem ("key2", null); 465 466 // Thrown from: 467 // at System.Runtime.Caching.MemoryCacheEntry..ctor(String key, Object value, DateTimeOffset absExp, TimeSpan slidingExp, CacheItemPriority priority, Collection`1 dependencies, CacheEntryRemovedCallback removedCallback, MemoryCache cache) 468 // at System.Runtime.Caching.MemoryCache.AddOrGetExistingInternal(String key, Object value, CacheItemPolicy policy) 469 // at System.Runtime.Caching.MemoryCache.AddOrGetExisting(CacheItem item, CacheItemPolicy policy) 470 // at MonoTests.System.Runtime.Caching.MemoryCacheTest.AddOrGetExisting_CacheItem_CacheItemPolicy() in C:\Users\grendel\documents\visual studio 2010\Projects\System.Runtime.Caching.Test\System.Runtime.Caching.Test\System.Runtime.Caching\MemoryCacheTest.cs:line 211 471 Assert.Throws<ArgumentNullException> (() => { 472 ci2 = mc.AddOrGetExisting (ci, null); 473 }, "#B1"); 474 475 ci = new CacheItem ("key3", "value"); 476 var cip = new CacheItemPolicy (); 477 cip.UpdateCallback = (CacheEntryUpdateArguments arguments) => { }; 478 Assert.Throws<ArgumentException> (() => { 479 ci2 = mc.AddOrGetExisting (ci, cip); 480 }, "#B2"); 481 482 ci = new CacheItem ("key3", "value"); 483 cip = new CacheItemPolicy (); 484 cip.AbsoluteExpiration = DateTimeOffset.Now; 485 cip.SlidingExpiration = TimeSpan.FromTicks (DateTime.Now.Ticks); 486 Assert.Throws<ArgumentException> (() => { 487 mc.AddOrGetExisting (ci, cip); 488 }, "#B3"); 489 490 ci = new CacheItem ("key3", "value"); 491 cip = new CacheItemPolicy (); 492 cip.SlidingExpiration = TimeSpan.MinValue; 493 Assert.Throws<ArgumentOutOfRangeException> (() => { 494 mc.AddOrGetExisting (ci, cip); 495 }, "#B4-1"); 496 497 ci = new CacheItem ("key4_#B4-2", "value"); 498 cip = new CacheItemPolicy (); 499 cip.SlidingExpiration = TimeSpan.FromTicks (0L); 500 mc.AddOrGetExisting (ci, cip); 501 Assert.IsTrue (mc.Contains ("key4_#B4-2"), "#B4-2"); 502 503 ci = new CacheItem ("key3", "value"); 504 cip = new CacheItemPolicy (); 505 cip.SlidingExpiration = TimeSpan.FromDays (500); 506 Assert.Throws<ArgumentOutOfRangeException> (() => { 507 mc.AddOrGetExisting (ci, cip); 508 }, "#B5-1"); 509 510 ci = new CacheItem ("key5_#B5-2", "value"); 511 cip = new CacheItemPolicy (); 512 cip.SlidingExpiration = TimeSpan.FromDays (365); 513 mc.AddOrGetExisting (ci, cip); 514 Assert.IsTrue (mc.Contains ("key5_#B5-2"), "#B5-2"); 515 516 ci = new CacheItem ("key3", "value"); 517 cip = new CacheItemPolicy (); 518 cip.Priority = (CacheItemPriority)20; 519 Assert.Throws<ArgumentOutOfRangeException> (() => { 520 mc.AddOrGetExisting (ci, cip); 521 }, "#B6"); 522 523 ci = new CacheItem ("key3_B7", "value"); 524 cip = new CacheItemPolicy (); 525 cip.RemovedCallback = (CacheEntryRemovedArguments arguments) => { }; 526 ci2 = mc.AddOrGetExisting (ci, cip); 527 Assert.IsTrue (mc.Contains ("key3_B7"), "#B7"); 528 529 // LAMESPEC: MSDN says it should return null if the entry does not exist yet. 530 // 531 Assert.IsNotNull (ci2, "#C1-1"); 532 Assert.AreNotEqual (ci, ci2, "#C1-2"); 533 Assert.IsNull (ci2.Value, "#C1-3"); 534 Assert.IsTrue (mc.Contains (ci.Key), "#C1-4"); 535 Assert.AreEqual (ci.Key, ci2.Key, "#C1-5"); 536 537 // The entry is never inserted as its expiration date is before now 538 ci = new CacheItem ("key_D1", "value_D1"); 539 cip = new CacheItemPolicy (); 540 cip.AbsoluteExpiration = DateTimeOffset.MinValue; 541 ci2 = mc.AddOrGetExisting (ci, cip); 542 Assert.IsFalse (mc.Contains ("key_D1"), "#D1-1"); 543 Assert.IsNotNull (ci2, "#D1-2"); 544 Assert.IsNull (ci2.Value, "#D1-3"); 545 Assert.AreEqual ("key_D1", ci2.Key, "#D1-4"); 546 547 mc.Calls.Clear (); 548 ci = new CacheItem ("key_D2", "value_D2"); 549 cip = new CacheItemPolicy (); 550 cip.AbsoluteExpiration = DateTimeOffset.MaxValue; 551 mc.AddOrGetExisting (ci, cip); 552 Assert.IsTrue (mc.Contains ("key_D2"), "#D2-1"); 553 Assert.AreEqual (2, mc.Calls.Count, "#D2-2"); 554 Assert.AreEqual ("AddOrGetExisting (CacheItem item, CacheItemPolicy policy)", mc.Calls [0], "#D2-3"); 555 } 556 557 [Test] Set_String_Object_CacheItemPolicy_String()558 public void Set_String_Object_CacheItemPolicy_String () 559 { 560 var mc = new PokerMemoryCache ("MyCache"); 561 562 Assert.Throws<NotSupportedException> (() => { 563 mc.Set ("key", "value", new CacheItemPolicy (), "region"); 564 }, "#A1-1"); 565 566 Assert.Throws<ArgumentNullException> (() => { 567 mc.Set (null, "value", new CacheItemPolicy ()); 568 }, "#A1-2"); 569 570 Assert.Throws<ArgumentNullException> (() => { 571 mc.Set ("key", null, new CacheItemPolicy ()); 572 }, "#A1-3"); 573 574 var cip = new CacheItemPolicy (); 575 cip.UpdateCallback = (CacheEntryUpdateArguments arguments) => { }; 576 cip.RemovedCallback = (CacheEntryRemovedArguments arguments) => { }; 577 Assert.Throws<ArgumentException> (() => { 578 mc.Set ("key", "value", cip); 579 }, "#A1-4"); 580 581 cip = new CacheItemPolicy (); 582 cip.SlidingExpiration = TimeSpan.MinValue; 583 Assert.Throws<ArgumentOutOfRangeException> (() => { 584 mc.Set ("key", "value", cip); 585 }, "#A1-5"); 586 587 cip = new CacheItemPolicy (); 588 cip.SlidingExpiration = TimeSpan.FromTicks (0L); 589 mc.Set ("key_A1-6", "value", cip); 590 Assert.IsTrue (mc.Contains ("key_A1-6"), "#A1-6"); 591 592 cip = new CacheItemPolicy (); 593 cip.SlidingExpiration = TimeSpan.FromDays (500); 594 Assert.Throws<ArgumentOutOfRangeException> (() => { 595 mc.Set ("key", "value", cip); 596 }, "#A1-7"); 597 598 cip = new CacheItemPolicy (); 599 cip.SlidingExpiration = TimeSpan.FromDays (365); 600 mc.Set ("key_A1-8", "value", cip); 601 Assert.IsTrue (mc.Contains ("key_A1-8"), "#A1-8"); 602 603 cip = new CacheItemPolicy (); 604 cip.Priority = (CacheItemPriority) 20; 605 Assert.Throws<ArgumentOutOfRangeException> (() => { 606 mc.Set ("key", "value", cip); 607 }, "#A1-9"); 608 609 cip = new CacheItemPolicy (); 610 cip.RemovedCallback = (CacheEntryRemovedArguments arguments) => { }; 611 mc.Set ("key_A2", "value_A2", cip); 612 Assert.IsTrue (mc.Contains ("key_A2"), "#A2"); 613 614 mc.Set ("key_A3", "value_A3", new CacheItemPolicy ()); 615 Assert.IsTrue (mc.Contains ("key_A3"), "#A3-1"); 616 Assert.AreEqual ("value_A3", mc.Get ("key_A3"), "#A3-2"); 617 618 // The entry is never inserted as its expiration date is before now 619 cip = new CacheItemPolicy (); 620 cip.AbsoluteExpiration = DateTimeOffset.MinValue; 621 mc.Set ("key_A4", "value_A4", cip); 622 Assert.IsFalse (mc.Contains ("key_A4"), "#A4"); 623 624 mc.Calls.Clear (); 625 cip = new CacheItemPolicy (); 626 cip.AbsoluteExpiration = DateTimeOffset.MaxValue; 627 mc.Set ("key_A5", "value_A5", cip); 628 Assert.IsTrue (mc.Contains ("key_A5"), "#A5-1"); 629 Assert.AreEqual (2, mc.Calls.Count, "#A5-2"); 630 Assert.AreEqual ("Set (string key, object value, CacheItemPolicy policy, string regionName = null)", mc.Calls [0], "#A5-3"); 631 } 632 633 [Test] Set_String_Object_DateTimeOffset_String()634 public void Set_String_Object_DateTimeOffset_String () 635 { 636 var mc = new PokerMemoryCache ("MyCache"); 637 638 Assert.Throws<NotSupportedException> (() => { 639 mc.Set ("key", "value", DateTimeOffset.MaxValue, "region"); 640 }, "#A1-1"); 641 642 Assert.Throws<ArgumentNullException> (() => { 643 mc.Set (null, "value", DateTimeOffset.MaxValue); 644 }, "#A1-2"); 645 646 Assert.Throws<ArgumentNullException> (() => { 647 mc.Set ("key", null, DateTimeOffset.MaxValue); 648 }, "#A1-3"); 649 650 // The entry is never inserted as its expiration date is before now 651 mc.Set ("key_A2", "value_A2", DateTimeOffset.MinValue); 652 Assert.IsFalse (mc.Contains ("key_A2"), "#A2"); 653 654 mc.Calls.Clear (); 655 mc.Set ("key", "value", DateTimeOffset.MaxValue); 656 657 Assert.AreEqual (2, mc.Calls.Count, "#A2-1"); 658 Assert.AreEqual ("Set (string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)", mc.Calls [0], "#A2-2"); 659 Assert.AreEqual ("Set (string key, object value, CacheItemPolicy policy, string regionName = null)", mc.Calls [1], "#A2-3"); 660 } 661 662 [Test] Set_CacheItem_CacheItemPolicy()663 public void Set_CacheItem_CacheItemPolicy () 664 { 665 var mc = new PokerMemoryCache ("MyCache"); 666 667 Assert.Throws<ArgumentNullException> (() => { 668 mc.Set (null, new CacheItemPolicy ()); 669 }, "#A1-1"); 670 671 // Actually thrown from the Set (string, object, CacheItemPolicy, string) overload 672 var ci = new CacheItem (null, "value"); 673 Assert.Throws<ArgumentNullException> (() => { 674 mc.Set (ci, new CacheItemPolicy ()); 675 }, "#A1-2"); 676 677 ci = new CacheItem ("key", null); 678 Assert.Throws<ArgumentNullException> (() => { 679 mc.Set (ci, new CacheItemPolicy ()); 680 }, "#A1-3"); 681 682 ci = new CacheItem ("key", "value"); 683 var cip = new CacheItemPolicy (); 684 cip.UpdateCallback = (CacheEntryUpdateArguments arguments) => { }; 685 cip.RemovedCallback = (CacheEntryRemovedArguments arguments) => { }; 686 Assert.Throws<ArgumentException> (() => { 687 mc.Set (ci, cip); 688 }, "#A1-4"); 689 690 ci = new CacheItem ("key", "value"); 691 cip = new CacheItemPolicy (); 692 cip.SlidingExpiration = TimeSpan.MinValue; 693 Assert.Throws<ArgumentOutOfRangeException> (() => { 694 mc.Set (ci, cip); 695 }, "#A1-5"); 696 697 ci = new CacheItem ("key_A1-6", "value"); 698 cip = new CacheItemPolicy (); 699 cip.SlidingExpiration = TimeSpan.FromTicks (0L); 700 mc.Set (ci, cip); 701 Assert.IsTrue (mc.Contains ("key_A1-6"), "#A1-6"); 702 703 ci = new CacheItem ("key", "value"); 704 cip = new CacheItemPolicy (); 705 cip.SlidingExpiration = TimeSpan.FromDays (500); 706 Assert.Throws<ArgumentOutOfRangeException> (() => { 707 mc.Set (ci, cip); 708 }, "#A1-7"); 709 710 ci = new CacheItem ("key_A1-8", "value"); 711 cip = new CacheItemPolicy (); 712 cip.SlidingExpiration = TimeSpan.FromDays (365); 713 mc.Set (ci, cip); 714 Assert.IsTrue (mc.Contains ("key_A1-8"), "#A1-8"); 715 716 ci = new CacheItem ("key", "value"); 717 cip = new CacheItemPolicy (); 718 cip.Priority = (CacheItemPriority) 20; 719 Assert.Throws<ArgumentOutOfRangeException> (() => { 720 mc.Set (ci, cip); 721 }, "#A1-9"); 722 723 ci = new CacheItem ("key_A2", "value_A2"); 724 cip = new CacheItemPolicy (); 725 cip.RemovedCallback = (CacheEntryRemovedArguments arguments) => { }; 726 mc.Set (ci, cip); 727 Assert.IsTrue (mc.Contains ("key_A2"), "#A2"); 728 729 ci = new CacheItem ("key_A3", "value_A3"); 730 mc.Set (ci, new CacheItemPolicy ()); 731 Assert.IsTrue (mc.Contains ("key_A3"), "#A3-1"); 732 Assert.AreEqual ("value_A3", mc.Get ("key_A3"), "#A3-2"); 733 734 // The entry is never inserted as its expiration date is before now 735 ci = new CacheItem ("key_A4", "value"); 736 cip = new CacheItemPolicy (); 737 cip.AbsoluteExpiration = DateTimeOffset.MinValue; 738 mc.Set (ci, cip); 739 Assert.IsFalse (mc.Contains ("key_A4"), "#A4"); 740 741 ci = new CacheItem ("key_A5", "value"); 742 mc.Calls.Clear (); 743 mc.Set (ci, new CacheItemPolicy ()); 744 745 Assert.AreEqual (2, mc.Calls.Count, "#A5-1"); 746 Assert.AreEqual ("Set (CacheItem item, CacheItemPolicy policy)", mc.Calls [0], "#A5-2"); 747 Assert.AreEqual ("Set (string key, object value, CacheItemPolicy policy, string regionName = null)", mc.Calls [1], "#A5-3"); 748 } 749 750 [Test] Remove()751 public void Remove () 752 { 753 var mc = new PokerMemoryCache ("MyCache"); 754 755 Assert.Throws<NotSupportedException> (() => { 756 mc.Remove ("key", "region"); 757 }, "#A1-1"); 758 759 Assert.Throws<ArgumentNullException> (() => { 760 mc.Remove (null); 761 }, "#A1-2"); 762 763 bool callbackInvoked; 764 CacheEntryRemovedReason reason = (CacheEntryRemovedReason) 1000; 765 var cip = new CacheItemPolicy (); 766 cip.Priority = CacheItemPriority.NotRemovable; 767 mc.Set ("key2", "value1", cip); 768 object value = mc.Remove ("key2"); 769 770 Assert.IsNotNull (value, "#B1-1"); 771 Assert.IsFalse (mc.Contains ("key2"), "#B1-2"); 772 773 cip = new CacheItemPolicy (); 774 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 775 callbackInvoked = true; 776 reason = args.RemovedReason; 777 }; 778 779 mc.Set ("key", "value", cip); 780 callbackInvoked = false; 781 reason = (CacheEntryRemovedReason) 1000; 782 value = mc.Remove ("key"); 783 Assert.IsNotNull (value, "#C1-1"); 784 Assert.IsTrue (callbackInvoked, "#C1-2"); 785 Assert.AreEqual (CacheEntryRemovedReason.Removed, reason, "#C1-3"); 786 787 cip = new CacheItemPolicy (); 788 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 789 callbackInvoked = true; 790 reason = args.RemovedReason; 791 throw new ApplicationException ("test"); 792 }; 793 794 mc.Set ("key", "value", cip); 795 callbackInvoked = false; 796 reason = (CacheEntryRemovedReason) 1000; 797 value = mc.Remove ("key"); 798 Assert.IsNotNull (value, "#C2-1"); 799 Assert.IsTrue (callbackInvoked, "#C2-2"); 800 Assert.AreEqual (CacheEntryRemovedReason.Removed, reason, "#C2-3"); 801 802 // LAMESPEC: UpdateCallback is not called on remove 803 cip = new CacheItemPolicy (); 804 cip.UpdateCallback = (CacheEntryUpdateArguments args) => { 805 callbackInvoked = true; 806 reason = args.RemovedReason; 807 }; 808 809 mc.Set ("key", "value", cip); 810 callbackInvoked = false; 811 reason = (CacheEntryRemovedReason) 1000; 812 value = mc.Remove ("key"); 813 Assert.IsNotNull (value, "#D1-1"); 814 Assert.IsFalse (callbackInvoked, "#D1-2"); 815 816 cip = new CacheItemPolicy (); 817 cip.UpdateCallback = (CacheEntryUpdateArguments args) => { 818 callbackInvoked = true; 819 reason = args.RemovedReason; 820 throw new ApplicationException ("test"); 821 }; 822 823 mc.Set ("key", "value", cip); 824 callbackInvoked = false; 825 reason = (CacheEntryRemovedReason) 1000; 826 value = mc.Remove ("key"); 827 Assert.IsNotNull (value, "#D2-1"); 828 Assert.IsFalse (callbackInvoked, "#D2-2"); 829 } 830 831 [Test] TimedExpiration()832 public void TimedExpiration () 833 { 834 bool expired = false; 835 CacheEntryRemovedReason reason = CacheEntryRemovedReason.CacheSpecificEviction; 836 int sleepPeriod = 1100; 837 838 var mc = new PokerMemoryCache ("MyCache"); 839 var cip = new CacheItemPolicy (); 840 841 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 842 expired = true; 843 reason = args.RemovedReason; 844 }; 845 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (50); 846 mc.Set ("key", "value", cip); 847 Thread.Sleep (500); 848 849 Assert.IsFalse (expired, "#A1"); 850 object value = mc.Get ("key"); 851 852 Assert.IsNull (value, "#A2-1"); 853 Assert.IsTrue (expired, "#A2-2"); 854 Assert.AreEqual (CacheEntryRemovedReason.Expired, reason, "A2-3"); 855 856 expired = false; 857 cip = new CacheItemPolicy (); 858 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 859 expired = true; 860 reason = args.RemovedReason; 861 }; 862 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (50); 863 mc.Set ("key", "value", cip); 864 Thread.Sleep (sleepPeriod); 865 866 Assert.IsNull (mc.Get ("key"), "#A3-0"); 867 Assert.IsTrue (expired, "#A3-1"); 868 Assert.AreEqual (CacheEntryRemovedReason.Expired, reason, "#A3-2"); 869 870 int expiredCount = 0; 871 object expiredCountLock = new object (); 872 CacheEntryRemovedCallback removedCb = (CacheEntryRemovedArguments args) => { 873 lock (expiredCountLock) { 874 expiredCount++; 875 } 876 }; 877 878 cip = new CacheItemPolicy (); 879 cip.RemovedCallback = removedCb; 880 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (20); 881 mc.Set ("key1", "value1", cip); 882 883 cip = new CacheItemPolicy (); 884 cip.RemovedCallback = removedCb; 885 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (200); 886 mc.Set ("key2", "value2", cip); 887 888 cip = new CacheItemPolicy (); 889 cip.RemovedCallback = removedCb; 890 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (600); 891 mc.Set ("key3", "value3", cip); 892 893 cip = new CacheItemPolicy (); 894 cip.RemovedCallback = removedCb; 895 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (sleepPeriod + 500); 896 mc.Set ("key4", "value4", cip); 897 898 Thread.Sleep (sleepPeriod); 899 Assert.IsNull (mc.Get ("key1"), "#A4-1"); 900 Assert.IsNull (mc.Get ("key2"), "#A4-2"); 901 Assert.IsNull (mc.Get ("key3"), "#A4-3"); 902 Assert.IsNotNull (mc.Get ("key4"), "#A4-4"); 903 Assert.AreEqual (3, expiredCount, "#A4"); 904 } 905 906 [Test] GetEnumerator()907 public void GetEnumerator () 908 { 909 var mc = new PokerMemoryCache ("MyCache"); 910 911 // This one is a Hashtable enumerator 912 IEnumerator enumerator = ((IEnumerable) mc).GetEnumerator (); 913 914 // This one is a Dictionary <string, object> enumerator 915 IEnumerator enumerator2 = mc.DoGetEnumerator (); 916 917 Assert.IsNotNull (enumerator, "#A1-1"); 918 Assert.IsNotNull (enumerator2, "#A1-2"); 919 Assert.IsTrue (enumerator.GetType () != enumerator2.GetType (), "#A1-3"); 920 921 mc.Set ("key1", "value1", null); 922 mc.Set ("key2", "value2", null); 923 mc.Set ("key3", "value3", null); 924 925 bool expired = false; 926 var cip = new CacheItemPolicy (); 927 cip.AbsoluteExpiration = DateTime.Now.AddMilliseconds (50); 928 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 929 expired = true; 930 }; 931 932 mc.Set ("key4", "value4", cip); 933 Thread.Sleep (500); 934 935 enumerator = ((IEnumerable) mc).GetEnumerator (); 936 int count = 0; 937 while (enumerator.MoveNext ()) { 938 count++; 939 } 940 941 Assert.IsFalse (expired, "#A2-1"); 942 Assert.AreEqual (3, count, "#A2-2"); 943 944 expired = false; 945 cip = new CacheItemPolicy (); 946 cip.AbsoluteExpiration = DateTime.Now.AddMilliseconds (50); 947 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 948 expired = true; 949 }; 950 951 mc.Set ("key5", "value5", cip); 952 Thread.Sleep (500); 953 954 enumerator2 = mc.DoGetEnumerator (); 955 count = 0; 956 while (enumerator2.MoveNext ()) { 957 count++; 958 } 959 960 Assert.IsFalse (expired, "#A3-1"); 961 Assert.AreEqual (3, count, "#A3-2"); 962 } 963 964 [Test] GetValues()965 public void GetValues () 966 { 967 var mc = new PokerMemoryCache ("MyCache"); 968 969 Assert.Throws<ArgumentNullException> (() => { 970 mc.GetValues ((string[]) null); 971 }, "#A1-1"); 972 973 Assert.Throws<NotSupportedException> (() => { 974 mc.GetValues (new string[] {}, "region"); 975 }, "#A1-2"); 976 977 Assert.Throws<ArgumentException> (() => { 978 mc.GetValues (new string [] { "key", null }); 979 }, "#A1-3"); 980 981 IDictionary<string, object> value = mc.GetValues (new string[] {}); 982 Assert.IsNull (value, "#A2"); 983 984 mc.Set ("key1", "value1", null); 985 mc.Set ("key2", "value2", null); 986 mc.Set ("key3", "value3", null); 987 988 Assert.IsTrue (mc.Contains ("key1"), "#A3-1"); 989 Assert.IsTrue (mc.Contains ("key2"), "#A3-2"); 990 Assert.IsTrue (mc.Contains ("key3"), "#A3-2"); 991 992 value = mc.GetValues (new string [] { "key1", "key3" }); 993 Assert.IsNotNull (value, "#A4-1"); 994 Assert.AreEqual (2, value.Count, "#A4-2"); 995 Assert.AreEqual ("value1", value ["key1"], "#A4-3"); 996 Assert.AreEqual ("value3", value ["key3"], "#A4-4"); 997 Assert.AreEqual (typeof (Dictionary<string, object>), value.GetType (), "#A4-5"); 998 999 // LAMESPEC: MSDN says the number of items in the returned dictionary should be the same as in the 1000 // 'keys' collection - this is not the case. The returned dictionary contains only entries for keys 1001 // that exist in the cache. 1002 value = mc.GetValues (new string [] { "key1", "key3", "nosuchkey" }); 1003 Assert.IsNotNull (value, "#A5-1"); 1004 Assert.AreEqual (2, value.Count, "#A5-2"); 1005 Assert.AreEqual ("value1", value ["key1"], "#A5-3"); 1006 Assert.AreEqual ("value3", value ["key3"], "#A5-4"); 1007 Assert.IsFalse (value.ContainsKey ("Key1"), "#A5-5"); 1008 } 1009 1010 [Test] Get()1011 public void Get () 1012 { 1013 var mc = new PokerMemoryCache ("MyCache"); 1014 1015 Assert.Throws<NotSupportedException> (() => { 1016 mc.Get ("key", "region"); 1017 }, "#A1-1"); 1018 1019 Assert.Throws<ArgumentNullException> (() => { 1020 mc.Get (null); 1021 }, "#A1-2"); 1022 1023 object value; 1024 mc.Set ("key", "value", null); 1025 value = mc.Get ("key"); 1026 Assert.IsNotNull (value, "#A2-1"); 1027 Assert.AreEqual ("value", value, "#A2-2"); 1028 1029 value = mc.Get ("nosuchkey"); 1030 Assert.IsNull (value, "#A3"); 1031 1032 var cip = new CacheItemPolicy (); 1033 bool callbackInvoked; 1034 CacheEntryRemovedReason reason = (CacheEntryRemovedReason)1000; 1035 1036 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (50); 1037 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 1038 callbackInvoked = true; 1039 reason = args.RemovedReason; 1040 }; 1041 mc.Set ("key", "value", cip); 1042 Thread.Sleep (500); 1043 1044 callbackInvoked = false; 1045 reason = (CacheEntryRemovedReason) 1000; 1046 value = mc.Get ("key"); 1047 Assert.IsNull (value, "#B1-1"); 1048 Assert.IsTrue (callbackInvoked, "#B1-2"); 1049 Assert.AreEqual (CacheEntryRemovedReason.Expired, reason, "#B1-3"); 1050 1051 cip = new CacheItemPolicy (); 1052 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (50); 1053 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 1054 callbackInvoked = true; 1055 reason = args.RemovedReason; 1056 throw new ApplicationException ("test"); 1057 }; 1058 1059 mc.Set ("key", "value", cip); 1060 Thread.Sleep (500); 1061 1062 callbackInvoked = false; 1063 reason = (CacheEntryRemovedReason) 1000; 1064 value = mc.Get ("key"); 1065 Assert.IsNull (value, "#B2-1"); 1066 Assert.IsTrue (callbackInvoked, "#B2-2"); 1067 Assert.AreEqual (CacheEntryRemovedReason.Expired, reason, "#B2-3"); 1068 } 1069 1070 [Test] GetCacheItem()1071 public void GetCacheItem () 1072 { 1073 var mc = new PokerMemoryCache ("MyCache"); 1074 1075 Assert.Throws<NotSupportedException> (() => { 1076 mc.GetCacheItem ("key", "region"); 1077 }, "#A1-1"); 1078 1079 Assert.Throws<ArgumentNullException> (() => { 1080 mc.GetCacheItem (null); 1081 }, "#A1-2"); 1082 1083 CacheItem value; 1084 mc.Set ("key", "value", null); 1085 value = mc.GetCacheItem ("key"); 1086 Assert.IsNotNull (value, "#A2-1"); 1087 Assert.AreEqual ("value", value.Value, "#A2-2"); 1088 Assert.AreEqual ("key", value.Key, "#A2-3"); 1089 1090 value = mc.GetCacheItem ("doesnotexist"); 1091 Assert.IsNull (value, "#A3"); 1092 1093 var cip = new CacheItemPolicy (); 1094 bool callbackInvoked; 1095 CacheEntryRemovedReason reason = (CacheEntryRemovedReason) 1000; 1096 1097 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (50); 1098 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 1099 callbackInvoked = true; 1100 reason = args.RemovedReason; 1101 }; 1102 mc.Set ("key", "value", cip); 1103 Thread.Sleep (500); 1104 1105 callbackInvoked = false; 1106 reason = (CacheEntryRemovedReason) 1000; 1107 value = mc.GetCacheItem ("key"); 1108 Assert.IsNull (value, "#B1-1"); 1109 Assert.IsTrue (callbackInvoked, "#B1-2"); 1110 Assert.AreEqual (CacheEntryRemovedReason.Expired, reason, "#B1-3"); 1111 1112 cip = new CacheItemPolicy (); 1113 cip.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds (50); 1114 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 1115 callbackInvoked = true; 1116 reason = args.RemovedReason; 1117 throw new ApplicationException ("test"); 1118 }; 1119 1120 mc.Set ("key", "value", cip); 1121 Thread.Sleep (500); 1122 1123 callbackInvoked = false; 1124 reason = (CacheEntryRemovedReason) 1000; 1125 value = mc.GetCacheItem ("key"); 1126 Assert.IsNull (value, "#B2-1"); 1127 Assert.IsTrue (callbackInvoked, "#B2-2"); 1128 Assert.AreEqual (CacheEntryRemovedReason.Expired, reason, "#B2-3"); 1129 } 1130 1131 [Test] ChangeMonitors()1132 public void ChangeMonitors () 1133 { 1134 bool removed = false; 1135 var mc = new PokerMemoryCache ("MyCache"); 1136 var cip = new CacheItemPolicy (); 1137 var monitor = new PokerChangeMonitor (); 1138 cip.ChangeMonitors.Add (monitor); 1139 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 1140 removed = true; 1141 }; 1142 1143 mc.Set ("key", "value", cip); 1144 Assert.AreEqual (0, monitor.Calls.Count, "#A1"); 1145 1146 monitor.SignalChange (); 1147 Assert.IsTrue (removed, "#A2"); 1148 1149 bool onChangedCalled = false; 1150 monitor = new PokerChangeMonitor (); 1151 monitor.NotifyOnChanged ((object state) => { 1152 onChangedCalled = true; 1153 }); 1154 1155 cip = new CacheItemPolicy (); 1156 cip.ChangeMonitors.Add (monitor); 1157 1158 // Thrown by ChangeMonitor.NotifyOnChanged 1159 Assert.Throws<InvalidOperationException> (() => { 1160 mc.Set ("key1", "value1", cip); 1161 }, "#A3"); 1162 } 1163 1164 // NOTE: on Windows with 2 or more CPUs this test will most probably fail. 1165 [Test] Trim()1166 public void Trim () 1167 { 1168 var config = new NameValueCollection (); 1169 config ["__MonoEmulateOneCPU"] = "true"; 1170 var mc = new MemoryCache ("MyCache", config); 1171 1172 for (int i = 0; i < 10; i++) 1173 mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); 1174 1175 Assert.AreEqual (10, mc.GetCount (), "#A1-1"); 1176 long trimmed = mc.Trim (50); 1177 Assert.AreEqual (5, trimmed, "#A1-2"); 1178 Assert.AreEqual (5, mc.GetCount (), "#A1-3"); 1179 1180 mc = new MemoryCache ("MyCache", config); 1181 // Only entries 11- are considered for removal 1182 for (int i = 0; i < 11; i++) 1183 mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); 1184 1185 Assert.AreEqual (11, mc.GetCount (), "#A2-1"); 1186 trimmed = mc.Trim (50); 1187 Assert.AreEqual (6, trimmed, "#A2-2"); 1188 Assert.AreEqual (5, mc.GetCount (), "#A2-3"); 1189 1190 mc = new MemoryCache ("MyCache", config); 1191 // Only entries 11- are considered for removal 1192 for (int i = 0; i < 125; i++) 1193 mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); 1194 1195 Assert.AreEqual (125, mc.GetCount (), "#A3-1"); 1196 trimmed = mc.Trim (50); 1197 Assert.AreEqual (63, trimmed, "#A3-2"); 1198 Assert.AreEqual (62, mc.GetCount (), "#A3-3"); 1199 1200 // Testing the removal order 1201 mc = new MemoryCache ("MyCache", config); 1202 var removed = new List <string> (); 1203 var cip = new CacheItemPolicy (); 1204 cip.RemovedCallback = (CacheEntryRemovedArguments args) => { 1205 removed.Add (args.CacheItem.Key); 1206 }; 1207 1208 for (int i = 0; i < 50; i++) 1209 mc.Set ("key" + i.ToString (), "value" + i.ToString (), cip); 1210 1211 object value; 1212 for (int i = 0; i < 50; i++) 1213 value = mc.Get ("key" + i.ToString ()); 1214 1215 trimmed = mc.Trim (50); 1216 Assert.AreEqual (25, mc.GetCount (), "#A4-1"); 1217 Assert.AreEqual (25, trimmed, "#A4-2"); 1218 Assert.AreEqual (25, removed.Count, "#A4-3"); 1219 1220 for (int i = 0; i < 25; i++) 1221 Assert.AreEqual ("key" + i.ToString (), removed [i], "#A5-" + i.ToString ()); 1222 } 1223 1224 [Test] TestCacheShrink()1225 public void TestCacheShrink () 1226 { 1227 const int HEAP_RESIZE_THRESHOLD = 8192 + 2; 1228 const int HEAP_RESIZE_SHORT_ENTRIES = 2048; 1229 const int HEAP_RESIZE_LONG_ENTRIES = HEAP_RESIZE_THRESHOLD - HEAP_RESIZE_SHORT_ENTRIES; 1230 1231 var config = new NameValueCollection (); 1232 config["cacheMemoryLimitMegabytes"] = 0.ToString (); 1233 config["physicalMemoryLimitPercentage"] = 100.ToString (); 1234 config["pollingInterval"] = new TimeSpan (0, 0, 1).ToString (); 1235 1236 using (var mc = new MemoryCache ("TestCacheShrink", config)) { 1237 Assert.AreEqual (0, mc.GetCount (), "#CS1"); 1238 1239 // add some short duration entries 1240 for (int i = 0; i < HEAP_RESIZE_SHORT_ENTRIES; i++) { 1241 var expireAt = DateTimeOffset.Now.AddSeconds (3); 1242 mc.Add ("short-" + i, i.ToString (), expireAt); 1243 } 1244 1245 Assert.AreEqual (HEAP_RESIZE_SHORT_ENTRIES, mc.GetCount (), "#CS2"); 1246 1247 // add some long duration entries 1248 for (int i = 0; i < HEAP_RESIZE_LONG_ENTRIES; i++) { 1249 var expireAt = DateTimeOffset.Now.AddSeconds (12); 1250 mc.Add ("long-" + i, i.ToString (), expireAt); 1251 } 1252 1253 Assert.AreEqual (HEAP_RESIZE_LONG_ENTRIES + HEAP_RESIZE_SHORT_ENTRIES, mc.GetCount(), "#CS3"); 1254 1255 // wait for the cache thread to expire the short duration items, this will also shrink the size of the cache 1256 global::System.Threading.Thread.Sleep (5 * 1000); 1257 1258 for (int i = 0; i < HEAP_RESIZE_SHORT_ENTRIES; i++) { 1259 Assert.IsNull (mc.Get ("short-" + i), "#CS4-" + i); 1260 } 1261 Assert.AreEqual (HEAP_RESIZE_LONG_ENTRIES, mc.GetCount (), "#CS4"); 1262 1263 // add some new items into the cache, this will grow the cache again 1264 for (int i = 0; i < HEAP_RESIZE_LONG_ENTRIES; i++) { 1265 mc.Add("final-" + i, i.ToString (), DateTimeOffset.Now.AddSeconds (4)); 1266 } 1267 1268 Assert.AreEqual (HEAP_RESIZE_LONG_ENTRIES + HEAP_RESIZE_LONG_ENTRIES, mc.GetCount (), "#CS5"); 1269 } 1270 } 1271 1272 [Test] TestExpiredGetValues()1273 public void TestExpiredGetValues () 1274 { 1275 var config = new NameValueCollection (); 1276 config["cacheMemoryLimitMegabytes"] = 0.ToString (); 1277 config["physicalMemoryLimitPercentage"] = 100.ToString (); 1278 config["pollingInterval"] = new TimeSpan (0, 0, 10).ToString (); 1279 1280 using (var mc = new MemoryCache ("TestExpiredGetValues", config)) { 1281 Assert.AreEqual (0, mc.GetCount (), "#EGV1"); 1282 1283 var keys = new List<string> (); 1284 1285 // add some short duration entries 1286 for (int i = 0; i < 10; i++) { 1287 var key = "short-" + i; 1288 var expireAt = DateTimeOffset.Now.AddSeconds (1); 1289 mc.Add (key, i.ToString (), expireAt); 1290 1291 keys.Add (key); 1292 } 1293 1294 Assert.AreEqual (10, mc.GetCount (), "#EGV2"); 1295 1296 global::System.Threading.Thread.Sleep (4 * 1000); 1297 1298 // we have waited but the items won't be expired by the timer since it wont have fired yet 1299 Assert.AreEqual (10, mc.GetCount (), "#EGV3"); 1300 1301 // calling GetValues() will expire the items since we are now past their expiresAt 1302 mc.GetValues (keys); 1303 1304 Assert.AreEqual (0, mc.GetCount (), "#EGV4"); 1305 } 1306 } 1307 1308 [Test] TestCacheExpiryOrdering()1309 public void TestCacheExpiryOrdering () 1310 { 1311 var config = new NameValueCollection (); 1312 config["cacheMemoryLimitMegabytes"] = 0.ToString (); 1313 config["physicalMemoryLimitPercentage"] = 100.ToString (); 1314 config["pollingInterval"] = new TimeSpan (0, 0, 1).ToString (); 1315 1316 using (var mc = new MemoryCache ("TestCacheExpiryOrdering", config)) { 1317 Assert.AreEqual (0, mc.GetCount (), "#CEO1"); 1318 1319 // add long lived items into the cache first 1320 for (int i = 0; i < 100; i++) { 1321 var cip = new CacheItemPolicy (); 1322 cip.SlidingExpiration = new TimeSpan (0, 0, 10); 1323 mc.Add ("long-" + i, i, cip); 1324 } 1325 1326 Assert.AreEqual (100, mc.GetCount (), "#CEO2"); 1327 1328 // add shorter lived items into the cache, these should expire first 1329 for (int i = 0; i < 100; i++) { 1330 var cip = new CacheItemPolicy (); 1331 cip.SlidingExpiration = new TimeSpan(0, 0, 1); 1332 mc.Add ("short-" + i, i, cip); 1333 } 1334 1335 Assert.AreEqual (200, mc.GetCount (), "#CEO3"); 1336 1337 global::System.Threading.Thread.Sleep (4 * 1000); 1338 1339 for (int i = 0; i < 100; i++) { 1340 Assert.IsNull (mc.Get ("short-" + i), "#CEO4-" + i); 1341 } 1342 Assert.AreEqual (100, mc.GetCount (), "#CEO4"); 1343 } 1344 } 1345 1346 [Test] TestCacheSliding()1347 public void TestCacheSliding () 1348 { 1349 var config = new NameValueCollection (); 1350 config["cacheMemoryLimitMegabytes"] = 0.ToString (); 1351 config["physicalMemoryLimitPercentage"] = 100.ToString (); 1352 config["pollingInterval"] = new TimeSpan (0, 0, 1).ToString (); 1353 1354 using (var mc = new MemoryCache ("TestCacheSliding", config)) { 1355 Assert.AreEqual (0, mc.GetCount (), "#CSL1"); 1356 1357 var cip = new CacheItemPolicy(); 1358 // The sliding expiration timeout has to be greater than 1 second because 1359 // .NET implementation ignores timeouts updates smaller than 1360 // CacheExpires.MIN_UPDATE_DELTA which is equal to 1. 1361 cip.SlidingExpiration = new TimeSpan (0, 0, 2); 1362 mc.Add("slidingtest", "42", cip); 1363 1364 mc.Add("expire1", "1", cip); 1365 mc.Add("expire2", "2", cip); 1366 mc.Add("expire3", "3", cip); 1367 mc.Add("expire4", "4", cip); 1368 mc.Add("expire5", "5", cip); 1369 1370 Assert.AreEqual (6, mc.GetCount (), "#CSL2"); 1371 1372 for (int i = 0; i < 50; i++) { 1373 global::System.Threading.Thread.Sleep (100); 1374 1375 var item = mc.Get ("slidingtest"); 1376 Assert.AreNotEqual (null, item, "#CSL3-" + i); 1377 } 1378 1379 Assert.IsNull (mc.Get ("expire1"), "#CSL4-1"); 1380 Assert.IsNull (mc.Get ("expire2"), "#CSL4-2"); 1381 Assert.IsNull (mc.Get ("expire3"), "#CSL4-3"); 1382 Assert.IsNull (mc.Get ("expire4"), "#CSL4-4"); 1383 Assert.IsNull (mc.Get ("expire5"), "#CSL4-5"); 1384 Assert.AreEqual (1, mc.GetCount (), "#CSL4"); 1385 1386 global::System.Threading.Thread.Sleep (4 * 1000); 1387 1388 Assert.IsNull (mc.Get ("slidingtest"), "#CSL5a"); 1389 Assert.AreEqual (0, mc.GetCount (), "#CSL5"); 1390 } 1391 } 1392 } 1393 } 1394