Files
Umbraco-CMS/src/Umbraco.Tests/Logging/RingBufferTest.cs

150 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Umbraco.Core.Logging;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
[TestFixture]
public class RingBufferTest
{
[Test]
public void PerfTest()
{
RingBuffer<string> ringBuffer = new RingBuffer<string>(1000);
Stopwatch ringWatch = new Stopwatch();
ringWatch.Start();
for (int i = 0; i < 1000000; i++)
{
ringBuffer.Enqueue("StringOfFun");
}
ringWatch.Stop();
Assert.That(ringWatch.ElapsedMilliseconds, Is.LessThan(150));
}
[Test]
public void PerfTestThreads()
{
RingBuffer<string> ringBuffer = new RingBuffer<string>(1000);
Stopwatch ringWatch = new Stopwatch();
List<Task> ringTasks = new List<Task>();
CancellationTokenSource cancelationTokenSource = new CancellationTokenSource();
CancellationToken cancelationToken = cancelationTokenSource.Token;
for (int t = 0; t < 10; t++)
{
ringTasks.Add(new Task(() =>
{
for (int i = 0; i < 1000000; i++)
{
ringBuffer.Enqueue("StringOfFun");
}
}, cancelationToken));
}
ringWatch.Start();
ringTasks.ForEach(t => t.Start());
var allTasks = ringTasks.ToArray();
Task.WaitAny(allTasks);
ringWatch.Stop();
//Cancel tasks to avoid System.AppDominUnloadException which is caused when the domain is unloaded
//and threads created in the domain are not stopped.
//Do this before assertions because they may throw an exception causing the thread cancellation to not happen.
cancelationTokenSource.Cancel();
try
{
Task.WaitAll(allTasks);
}
catch (AggregateException)
{
//Don't care about cancellation Exceptions.
}
//Tolerance at 500 was too low
ringTasks.ForEach(t => t.Dispose());
Assert.That(ringWatch.ElapsedMilliseconds, Is.LessThan(1000));
}
[Test]
public void PerfTestThreadsWithDequeues()
{
RingBuffer<string> ringBuffer = new RingBuffer<string>(1000);
Stopwatch ringWatch = new Stopwatch();
List<Task> ringTasks = new List<Task>();
CancellationTokenSource cancelationTokenSource = new CancellationTokenSource();
CancellationToken cancelationToken = cancelationTokenSource.Token;
for (int t = 0; t < 10; t++)
{
ringTasks.Add(new Task(() =>
{
for (int i = 0; i < 1000000; i++)
{
ringBuffer.Enqueue("StringOfFun");
}
}, cancelationToken));
}
for (int t = 0; t < 10; t++)
{
ringTasks.Add(new Task(() =>
{
for (int i = 0; i < 1000000; i++)
{
string foo;
ringBuffer.TryDequeue(out foo);
}
}));
}
ringWatch.Start();
ringTasks.ForEach(t => t.Start());
var allTasks = ringTasks.ToArray();
Task.WaitAny(allTasks);
ringWatch.Stop();
//Cancel tasks to avoid System.AppDominUnloadException which is caused when the domain is unloaded
//and threads created in the domain are not stopped.
//Do this before assertions because they may throw an exception causing the thread cancellation to not happen.
cancelationTokenSource.Cancel();
try
{
Task.WaitAll(allTasks);
}
catch (AggregateException)
{
//Don't care about cancellation Exceptions.
}
ringTasks.ForEach(t => t.Dispose());
Assert.That(ringWatch.ElapsedMilliseconds, Is.LessThan(800));
}
[Test]
public void WhenRingSizeLimitIsHit_ItemsAreDequeued()
{
// Arrange
const int limit = 2;
object object1 = "one";
object object2 = "two";
object object3 = "three";
RingBuffer<object> queue = new RingBuffer<object>(limit);
// Act
queue.Enqueue(object1);
queue.Enqueue(object2);
queue.Enqueue(object3);
// Assert
object value;
queue.TryDequeue(out value);
Assert.That(value, Is.EqualTo(object2));
queue.TryDequeue(out value);
Assert.That(value, Is.EqualTo(object3));
queue.TryDequeue(out value);
Assert.That(value, Is.Null);
}
}
}