blob: bf2849e4a29d171dab2595695d1dc1e51c4a1611 [file] [log] [blame]
/*
* 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.Core.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cluster;
using Apache.Ignite.Core.Discovery.Tcp;
using Apache.Ignite.Core.Discovery.Tcp.Static;
using Apache.Ignite.Core.Impl;
using Apache.Ignite.Core.Impl.Binary;
using NUnit.Framework;
/// <summary>
/// Test utility methods.
/// </summary>
public static partial class TestUtils
{
/** Indicates long running and/or memory/cpu intensive test. */
public const string CategoryIntensive = "LONG_TEST";
/** Indicates examples tests. */
public const string CategoryExamples = "EXAMPLES_TEST";
/** */
private const int DfltBusywaitSleepInterval = 200;
/** Work dir. */
private static readonly string WorkDir =
// ReSharper disable once AssignNullToNotNullAttribute
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ignite_work");
/** */
private static readonly IList<string> TestJvmOpts = Environment.Is64BitProcess
? new List<string>
{
"-XX:+HeapDumpOnOutOfMemoryError",
"-Xms1g",
"-Xmx4g",
"-ea",
"-DIGNITE_QUIET=true",
"-Duser.timezone=UTC"
}
: new List<string>
{
"-XX:+HeapDumpOnOutOfMemoryError",
"-Xms64m",
"-Xmx99m",
"-ea",
"-DIGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE=1000",
"-DIGNITE_QUIET=true",
"-Duser.timezone=UTC"
};
/** */
private static readonly IList<string> JvmDebugOpts =
new List<string> { "-Xdebug", "-Xnoagent", "-Djava.compiler=NONE", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" };
/** */
public static bool JvmDebug = true;
/** */
[ThreadStatic]
private static Random _random;
/** */
private static int _seed = Environment.TickCount;
/// <summary>
///
/// </summary>
public static Random Random
{
get { return _random ?? (_random = new Random(Interlocked.Increment(ref _seed))); }
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static IList<string> TestJavaOptions(bool? jvmDebug = null)
{
IList<string> ops = new List<string>(TestJvmOpts);
if (jvmDebug ?? JvmDebug)
{
foreach (string opt in JvmDebugOpts)
ops.Add(opt);
}
return ops;
}
/// <summary>
///
/// </summary>
/// <param name="action"></param>
/// <param name="threadNum"></param>
public static void RunMultiThreaded(Action action, int threadNum)
{
List<Thread> threads = new List<Thread>(threadNum);
var errors = new ConcurrentBag<Exception>();
for (int i = 0; i < threadNum; i++)
{
threads.Add(new Thread(() =>
{
try
{
action();
}
catch (Exception e)
{
errors.Add(e);
}
}));
}
foreach (Thread thread in threads)
thread.Start();
foreach (Thread thread in threads)
thread.Join();
foreach (var ex in errors)
Assert.Fail("Unexpected exception: " + ex);
}
/// <summary>
///
/// </summary>
/// <param name="action"></param>
/// <param name="threadNum"></param>
/// <param name="duration">Duration of test execution in seconds</param>
public static void RunMultiThreaded(Action action, int threadNum, int duration)
{
List<Thread> threads = new List<Thread>(threadNum);
var errors = new ConcurrentBag<Exception>();
bool stop = false;
for (int i = 0; i < threadNum; i++)
{
threads.Add(new Thread(() =>
{
try
{
while (true)
{
Thread.MemoryBarrier();
// ReSharper disable once AccessToModifiedClosure
if (stop)
break;
action();
}
}
catch (Exception e)
{
errors.Add(e);
}
}));
}
foreach (Thread thread in threads)
thread.Start();
Thread.Sleep(duration * 1000);
stop = true;
Thread.MemoryBarrier();
foreach (Thread thread in threads)
thread.Join();
foreach (var ex in errors)
Assert.Fail("Unexpected exception: " + ex);
}
/// <summary>
/// Wait for particular topology size.
/// </summary>
/// <param name="grid">Grid.</param>
/// <param name="size">Size.</param>
/// <param name="timeout">Timeout.</param>
/// <returns>
/// <c>True</c> if topology took required size.
/// </returns>
public static bool WaitTopology(this IIgnite grid, int size, int timeout = 30000)
{
int left = timeout;
while (true)
{
if (grid.GetCluster().GetNodes().Count != size)
{
if (left > 0)
{
Thread.Sleep(100);
left -= 100;
}
else
break;
}
else
return true;
}
return false;
}
/// <summary>
/// Waits for condition, polling in busy wait loop.
/// </summary>
/// <param name="cond">Condition.</param>
/// <param name="timeout">Timeout, in milliseconds.</param>
/// <returns>True if condition predicate returned true within interval; false otherwise.</returns>
public static bool WaitForCondition(Func<bool> cond, int timeout)
{
if (timeout <= 0)
return cond();
var maxTime = DateTime.Now.AddMilliseconds(timeout + DfltBusywaitSleepInterval);
while (DateTime.Now < maxTime)
{
if (cond())
return true;
Thread.Sleep(DfltBusywaitSleepInterval);
}
return false;
}
/// <summary>
/// Gets the static discovery.
/// </summary>
public static TcpDiscoverySpi GetStaticDiscovery()
{
return new TcpDiscoverySpi
{
IpFinder = new TcpDiscoveryStaticIpFinder
{
Endpoints = new[] { "127.0.0.1:47500" }
},
SocketTimeout = TimeSpan.FromSeconds(0.3)
};
}
/// <summary>
/// Gets the primary keys.
/// </summary>
public static IEnumerable<int> GetPrimaryKeys(IIgnite ignite, string cacheName,
IClusterNode node = null)
{
var aff = ignite.GetAffinity(cacheName);
node = node ?? ignite.GetCluster().GetLocalNode();
return Enumerable.Range(1, int.MaxValue).Where(x => aff.IsPrimary(node, x));
}
/// <summary>
/// Gets the primary key.
/// </summary>
public static int GetPrimaryKey(IIgnite ignite, string cacheName, IClusterNode node = null)
{
return GetPrimaryKeys(ignite, cacheName, node).First();
}
/// <summary>
/// Asserts that the handle registry is empty.
/// </summary>
/// <param name="timeout">Timeout, in milliseconds.</param>
/// <param name="grids">Grids to check.</param>
public static void AssertHandleRegistryIsEmpty(int timeout, params IIgnite[] grids)
{
foreach (var g in grids)
AssertHandleRegistryHasItems(g, 0, timeout);
}
/// <summary>
/// Asserts that the handle registry has specified number of entries.
/// </summary>
/// <param name="timeout">Timeout, in milliseconds.</param>
/// <param name="expectedCount">Expected item count.</param>
/// <param name="grids">Grids to check.</param>
public static void AssertHandleRegistryHasItems(int timeout, int expectedCount, params IIgnite[] grids)
{
foreach (var g in grids)
AssertHandleRegistryHasItems(g, expectedCount, timeout);
}
/// <summary>
/// Asserts that the handle registry has specified number of entries.
/// </summary>
/// <param name="grid">The grid to check.</param>
/// <param name="expectedCount">Expected item count.</param>
/// <param name="timeout">Timeout, in milliseconds.</param>
public static void AssertHandleRegistryHasItems(IIgnite grid, int expectedCount, int timeout)
{
var handleRegistry = ((Ignite)grid).HandleRegistry;
expectedCount++; // Skip default lifecycle bean
if (WaitForCondition(() => handleRegistry.Count == expectedCount, timeout))
return;
var items = handleRegistry.GetItems().Where(x => !(x.Value is LifecycleHandlerHolder)).ToList();
if (items.Any())
{
Assert.Fail("HandleRegistry is not empty in grid '{0}' (expected {1}, actual {2}):\n '{3}'",
grid.Name, expectedCount, handleRegistry.Count,
items.Select(x => x.ToString()).Aggregate((x, y) => x + "\n" + y));
}
}
/// <summary>
/// Serializes and deserializes back an object.
/// </summary>
public static T SerializeDeserialize<T>(T obj, bool raw = false)
{
var cfg = new BinaryConfiguration
{
Serializer = raw ? new BinaryReflectiveSerializer {RawMode = true} : null
};
var marsh = new Marshaller(cfg) { CompactFooter = false };
return marsh.Unmarshal<T>(marsh.Marshal(obj));
}
/// <summary>
/// Clears the work dir.
/// </summary>
public static void ClearWorkDir()
{
if (!Directory.Exists(WorkDir))
{
return;
}
// Delete everything we can. Some files may be locked.
foreach (var e in Directory.GetFileSystemEntries(WorkDir, "*", SearchOption.AllDirectories))
{
try
{
File.Delete(e);
}
catch (Exception)
{
// Ignore
}
try
{
Directory.Delete(e, true);
}
catch (Exception)
{
// Ignore
}
}
}
}
}