/* * MindTouch Dream - a distributed REST framework * Copyright (C) 2006-2014 MindTouch, Inc. * www.mindtouch.com [email protected] * * For community documentation and downloads visit mindtouch.com; * please review the licensing section. * * Licensed 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. */ using System; using System.Threading; using log4net; using MindTouch.Collections; using MindTouch.Threading; using NUnit.Framework; namespace MindTouch.Dream.Test.Collections { [TestFixture] public class LockFreeItemConsumerQueueTests { //--- Class Fields --- private static ILog _log = LogUtils.CreateLog(); //--- Methods --- #region --- Item Tests --- [Test] public void New_ItemCount() { var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryDequeue_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryEnqueue_ItemCount() { var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryEnqueue(42); Assert.AreEqual(1, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); } [Test] public void New_TryEnqueue_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryEnqueue(42); Assert.AreEqual(1, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(42, value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryDequeue_TryEnqueue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryEnqueue(42); Assert.AreEqual(1, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); } [Test] public void New_TryDequeue_TryEnqueue_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryEnqueue(42); Assert.AreEqual(1, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(42, value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryDequeue_TryEnqueue_TryDequeue_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryEnqueue(42); Assert.AreEqual(1, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(42, value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryEnqueue_x50_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryEnqueue(100 - i); } Assert.AreEqual(50, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.AreEqual(100 - i, value); } Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryEnqueue_x50_TryDequeue_x50_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryEnqueue(100 - i); } Assert.AreEqual(50, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.AreEqual(100 - i, value); } Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryEnqueue_x50_TryDequeue_x50_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryEnqueue(100 - i); } Assert.AreEqual(50, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.AreEqual(100 - i, value); } Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } [Test] public void New_TryDequeue_TryEnqueue_x50_TryDequeue_x50_TryDequeue_ItemCount() { int value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryEnqueue(100 - i); } Assert.AreEqual(50, q.ItemCount); Assert.IsFalse(q.ItemIsEmpty); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.AreEqual(100 - i, value); } Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); q.TryDequeue(out value); Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); } #endregion #region --- Consumer Tests --- [Test] public void New_ConsumerCount() { var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryDequeue_ConsumerCount() { var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); int value; q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryDequeue_TryDequeue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryEnqueue_ConsumerCount() { var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryEnqueue(x => { }); Assert.AreEqual(1, q.ConsumerCount); } [Test] public void New_TryEnqueue_TryDequeue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryEnqueue(x => { }); Assert.AreEqual(1, q.ConsumerCount); q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryDequeue_TryEnqueue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); q.TryEnqueue(x => { }); Assert.AreEqual(1, q.ConsumerCount); } [Test] public void New_TryDequeue_TryEnqueue_TryDequeue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); q.TryEnqueue(x => { }); Assert.AreEqual(1, q.ConsumerCount); q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryDequeue_TryEnqueue_TryDequeue_TryDequeue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); q.TryEnqueue(x => { }); Assert.AreEqual(1, q.ConsumerCount); q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryEnqueue_x50_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryEnqueue(x => { }); } Assert.AreEqual(50, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); } Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryEnqueue_x50_TryDequeue_x50_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryEnqueue(x => { }); } Assert.AreEqual(50, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); } Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryEnqueue_x50_TryDequeue_x50_TryDequeue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryEnqueue(x => { }); } Assert.AreEqual(50, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); } Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); } [Test] public void New_TryDequeue_TryEnqueue_x50_TryDequeue_x50_TryDequeue_ConsumerCount() { Action<int> value; var q = new LockFreeItemConsumerQueue<int>(); Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryEnqueue(x => { }); } Assert.AreEqual(50, q.ConsumerCount); for(int i = 0; i < 50; ++i) { q.TryDequeue(out value); Assert.IsAssignableFrom(typeof(Action<int>), value); } Assert.AreEqual(0, q.ConsumerCount); q.TryDequeue(out value); Assert.AreEqual(0, q.ConsumerCount); } #endregion [Test] public void New_TryEnqueueItem_x50_TryEnqueueConsumer_x50_ItemCount_ConsumerCount() { var q = new LockFreeItemConsumerQueue<int>(); var etp = new ElasticThreadPool(10, 10); // submit enqueue & dequeue work-items const int max = 10000; int count = max + 1; var e = new ManualResetEvent(false); int[] checks = new int[max]; for(int i = 0; i < max; ++i) { int j = i; etp.TryQueueWorkItem(() => { int k = Interlocked.Increment(ref checks[j]); Assert.AreEqual(1, k, "value for {0} was already increased", j); q.TryEnqueue(j); }); etp.TryQueueWorkItem(() => { q.TryEnqueue(x => { int k = Interlocked.Decrement(ref checks[x]); Assert.AreEqual(0, k, "value for {0} was already decreased", x); // ReSharper disable AccessToModifiedClosure if(Interlocked.Decrement(ref count) == 0) { // ReSharper restore AccessToModifiedClosure e.Set(); } }); }); } if(Interlocked.Decrement(ref count) == 0) { e.Set(); } if(!e.WaitOne(TimeSpan.FromSeconds(10))) { Assert.Fail("test timed out"); } for(int i = 0; i < max; ++i) { Assert.AreEqual(0, checks[i], "entry {0}", i); } Assert.AreEqual(0, q.ItemCount); Assert.IsTrue(q.ItemIsEmpty); Assert.AreEqual(0, q.ConsumerCount); Assert.IsTrue(q.ConsumerIsEmpty); } } }