blob: f3069187677f232d107412cd43240ccf99dd3e2a [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.
*/
#pragma warning disable 618
namespace Apache.Ignite.Core.Tests
{
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache;
using Apache.Ignite.Core.Cluster;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Compute;
using Apache.Ignite.Core.Impl.Common;
using Apache.Ignite.Core.Services;
using Apache.Ignite.Core.Transactions;
using NUnit.Framework;
/// <summary>
/// Tests grid exceptions propagation.
/// </summary>
public class ExceptionsTest
{
/** */
private const string ExceptionTask = "org.apache.ignite.platform.PlatformExceptionTask";
/// <summary>
/// After test.
/// </summary>
[TearDown]
public void TearDown()
{
Ignition.StopAll(true);
}
/// <summary>
/// Tests exceptions.
/// </summary>
[Test]
public void TestExceptions()
{
var grid = StartGrid();
Assert.Throws<ArgumentException>(() => grid.GetCache<object, object>("invalidCacheName"));
var e = Assert.Throws<ClusterGroupEmptyException>(() => grid.GetCluster().ForRemotes().GetMetrics());
Assert.IsNotNull(e.InnerException);
Assert.IsTrue(e.InnerException.Message.StartsWith(
"class org.apache.ignite.cluster.ClusterGroupEmptyException: Cluster group is empty."));
// Check all exceptions mapping.
var comp = grid.GetCompute();
CheckException<BinaryObjectException>(comp, "BinaryObjectException");
CheckException<IgniteException>(comp, "IgniteException");
CheckException<BinaryObjectException>(comp, "BinaryObjectException");
CheckException<ClusterTopologyException>(comp, "ClusterTopologyException");
CheckException<ComputeExecutionRejectedException>(comp, "ComputeExecutionRejectedException");
CheckException<ComputeJobFailoverException>(comp, "ComputeJobFailoverException");
CheckException<ComputeTaskCancelledException>(comp, "ComputeTaskCancelledException");
CheckException<ComputeTaskTimeoutException>(comp, "ComputeTaskTimeoutException");
CheckException<ComputeUserUndeclaredException>(comp, "ComputeUserUndeclaredException");
CheckException<TransactionOptimisticException>(comp, "TransactionOptimisticException");
CheckException<TransactionTimeoutException>(comp, "TransactionTimeoutException");
CheckException<TransactionRollbackException>(comp, "TransactionRollbackException");
CheckException<TransactionHeuristicException>(comp, "TransactionHeuristicException");
CheckException<TransactionDeadlockException>(comp, "TransactionDeadlockException");
CheckException<IgniteFutureCancelledException>(comp, "IgniteFutureCancelledException");
CheckException<ServiceDeploymentException>(comp, "ServiceDeploymentException");
// Check stopped grid.
grid.Dispose();
Assert.Throws<IgniteIllegalStateException>(() => grid.GetCache<object, object>("cache1"));
}
/// <summary>
/// Checks the exception.
/// </summary>
private static void CheckException<T>(ICompute comp, string name) where T : Exception
{
var ex = Assert.Throws<T>(() => comp.ExecuteJavaTask<string>(ExceptionTask, name));
var javaEx = ex.InnerException as JavaException;
Assert.IsNotNull(javaEx);
Assert.IsTrue(javaEx.Message.Contains("at " + ExceptionTask));
Assert.AreEqual(name, javaEx.JavaMessage);
Assert.IsTrue(javaEx.JavaClassName.EndsWith("." + name));
// Check serialization.
var formatter = new BinaryFormatter();
using (var ms = new MemoryStream())
{
#pragma warning disable SYSLIB0011 // BinaryFormatter is obsolete
formatter.Serialize(ms, ex);
ms.Seek(0, SeekOrigin.Begin);
var res = (T) formatter.Deserialize(ms);
Assert.AreEqual(ex.Message, res.Message);
Assert.AreEqual(ex.Source, res.Source);
Assert.AreEqual(ex.StackTrace, res.StackTrace);
Assert.AreEqual(ex.HelpLink, res.HelpLink);
var resJavaEx = res.InnerException as JavaException;
Assert.IsNotNull(resJavaEx);
Assert.AreEqual(javaEx.Message, resJavaEx.Message);
Assert.AreEqual(javaEx.JavaClassName, resJavaEx.JavaClassName);
Assert.AreEqual(javaEx.JavaMessage, resJavaEx.JavaMessage);
Assert.AreEqual(javaEx.StackTrace, resJavaEx.StackTrace);
Assert.AreEqual(javaEx.Source, resJavaEx.Source);
Assert.AreEqual(javaEx.HelpLink, resJavaEx.HelpLink);
#pragma warning restore SYSLIB0011 // BinaryFormatter is obsolete
}
}
/// <summary>
/// Tests CachePartialUpdateException keys propagation.
/// </summary>
[Test]
[Category(TestUtils.CategoryIntensive)]
public void TestPartialUpdateException()
{
// Primitive type
TestPartialUpdateException(false, (x, g) => x);
// User type
TestPartialUpdateException(false, (x, g) => new BinarizableEntry(x));
}
/// <summary>
/// Tests CachePartialUpdateException keys propagation in binary mode.
/// </summary>
[Test]
[Category(TestUtils.CategoryIntensive)]
public void TestPartialUpdateExceptionBinarizable()
{
// User type
TestPartialUpdateException(false, (x, g) => g.GetBinary().ToBinary<IBinaryObject>(new BinarizableEntry(x)));
}
/// <summary>
/// Tests CachePartialUpdateException serialization.
/// </summary>
[Test]
public void TestPartialUpdateExceptionSerialization()
{
// Inner exception
TestPartialUpdateExceptionSerialization(new CachePartialUpdateException("Msg",
new IgniteException("Inner msg")));
// Primitive keys
TestPartialUpdateExceptionSerialization(new CachePartialUpdateException("Msg", new object[] {1, 2, 3}));
// User type keys
TestPartialUpdateExceptionSerialization(new CachePartialUpdateException("Msg",
new object[]
{
new SerializableEntry(1),
new SerializableEntry(2),
new SerializableEntry(3)
}));
}
/// <summary>
/// Tests that all exceptions have mandatory constructors and are serializable.
/// </summary>
[Test]
public void TestAllExceptionsConstructors()
{
var types = typeof(IIgnite).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(Exception)));
foreach (var type in types)
{
Assert.IsTrue(type.IsSerializable, "Exception is not serializable: " + type);
// Default ctor.
var defCtor = type.GetConstructor(new Type[0]);
Assert.IsNotNull(defCtor);
var ex = (Exception) defCtor.Invoke(new object[0]);
Assert.AreEqual(string.Format("Exception of type '{0}' was thrown.", type.FullName), ex.Message);
// Message ctor.
var msgCtor = type.GetConstructor(new[] {typeof(string)});
Assert.IsNotNull(msgCtor);
ex = (Exception) msgCtor.Invoke(new object[] {"myMessage"});
Assert.AreEqual("myMessage", ex.Message);
// Serialization.
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011 // BinaryFormatter is obsolete
formatter.Serialize(stream, ex);
stream.Seek(0, SeekOrigin.Begin);
ex = (Exception) formatter.Deserialize(stream);
Assert.AreEqual("myMessage", ex.Message);
#pragma warning restore SYSLIB0011 // BinaryFormatter is obsolete
// Message+cause ctor.
var msgCauseCtor = type.GetConstructor(new[] { typeof(string), typeof(Exception) });
Assert.IsNotNull(msgCauseCtor);
ex = (Exception) msgCauseCtor.Invoke(new object[] {"myMessage", new Exception("innerEx")});
Assert.AreEqual("myMessage", ex.Message);
Assert.IsNotNull(ex.InnerException);
Assert.AreEqual("innerEx", ex.InnerException.Message);
}
}
/// <summary>
/// Tests CachePartialUpdateException serialization.
/// </summary>
private static void TestPartialUpdateExceptionSerialization(Exception ex)
{
var formatter = new BinaryFormatter();
var stream = new MemoryStream();
#pragma warning disable SYSLIB0011 // BinaryFormatter is obsolete
formatter.Serialize(stream, ex);
stream.Seek(0, SeekOrigin.Begin);
var ex0 = (Exception) formatter.Deserialize(stream);
#pragma warning restore SYSLIB0011 // BinaryFormatter is obsolete
var updateEx = ((CachePartialUpdateException) ex);
try
{
Assert.AreEqual(updateEx.GetFailedKeys<object>(),
((CachePartialUpdateException) ex0).GetFailedKeys<object>());
}
catch (Exception e)
{
if (typeof(IgniteException) != e.GetType())
throw;
}
while (ex != null && ex0 != null)
{
Assert.AreEqual(ex0.GetType(), ex.GetType());
Assert.AreEqual(ex.Message, ex0.Message);
ex = ex.InnerException;
ex0 = ex0.InnerException;
}
Assert.AreEqual(ex, ex0);
}
/// <summary>
/// Tests CachePartialUpdateException keys propagation.
/// </summary>
[Test]
[Category(TestUtils.CategoryIntensive)]
public void TestPartialUpdateExceptionAsync()
{
// Primitive type
TestPartialUpdateException(true, (x, g) => x);
// User type
TestPartialUpdateException(true, (x, g) => new BinarizableEntry(x));
}
/// <summary>
/// Tests CachePartialUpdateException keys propagation in binary mode.
/// </summary>
[Test]
[Category(TestUtils.CategoryIntensive)]
public void TestPartialUpdateExceptionAsyncBinarizable()
{
TestPartialUpdateException(true, (x, g) => g.GetBinary().ToBinary<IBinaryObject>(new BinarizableEntry(x)));
}
/// <summary>
/// Tests that invalid spring URL results in a meaningful exception.
/// </summary>
[Test]
public void TestInvalidSpringUrl()
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
SpringConfigUrl = "z:\\invalid.xml"
};
var ex = Assert.Throws<IgniteException>(() => Ignition.Start(cfg));
Assert.IsTrue(ex.ToString().Contains("Spring XML configuration path is invalid: z:\\invalid.xml"));
}
/// <summary>
/// Tests that invalid configuration parameter results in a meaningful exception.
/// </summary>
[Test]
public void TestInvalidConfig()
{
var disco = TestUtils.GetStaticDiscovery();
disco.SocketTimeout = TimeSpan.FromSeconds(-1); // set invalid timeout
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
DiscoverySpi = disco
};
var ex = Assert.Throws<IgniteException>(() => Ignition.Start(cfg));
Assert.IsTrue(ex.ToString().Contains("SPI parameter failed condition check: sockTimeout > 0"));
}
/// <summary>
/// Tests CachePartialUpdateException keys propagation.
/// </summary>
private static void TestPartialUpdateException<TK>(bool async, Func<int, IIgnite, TK> keyFunc)
{
using (var grid = StartGrid())
{
var cache = grid.GetOrCreateCache<TK, int>("partitioned_atomic").WithNoRetries();
if (typeof (TK) == typeof (IBinaryObject))
cache = cache.WithKeepBinary<TK, int>();
// Do cache puts in parallel
var putTask = TaskRunner.Run(() =>
{
try
{
// Do a lot of puts so that one fails during Ignite stop
for (var i = 0; i < 1000000; i++)
{
// ReSharper disable once AccessToDisposedClosure
// ReSharper disable once AccessToModifiedClosure
var dict = Enumerable.Range(1, 100).ToDictionary(k => keyFunc(k, grid), k => i);
if (async)
cache.PutAllAsync(dict).Wait();
else
cache.PutAll(dict);
}
}
catch (AggregateException ex)
{
CheckPartialUpdateException<TK>((CachePartialUpdateException) ex.InnerException);
return;
}
catch (CachePartialUpdateException ex)
{
CheckPartialUpdateException<TK>(ex);
return;
}
Assert.Fail("CachePartialUpdateException has not been thrown.");
});
while (true)
{
Thread.Sleep(1000);
Ignition.Stop("grid_2", true);
StartGrid("grid_2");
Thread.Sleep(1000);
if (putTask.Exception != null)
throw putTask.Exception;
if (putTask.IsCompleted)
return;
}
}
}
/// <summary>
/// Checks the partial update exception.
/// </summary>
private static void CheckPartialUpdateException<TK>(CachePartialUpdateException ex)
{
var failedKeys = ex.GetFailedKeys<TK>();
Assert.IsTrue(failedKeys.Any());
var failedKeysObj = ex.GetFailedKeys<object>();
Assert.IsTrue(failedKeysObj.Any());
}
/// <summary>
/// Starts the grid.
/// </summary>
private static IIgnite StartGrid(string gridName = null)
{
return Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
IgniteInstanceName = gridName,
BinaryConfiguration = new BinaryConfiguration
{
TypeConfigurations = new[]
{
new BinaryTypeConfiguration(typeof (BinarizableEntry))
}
}
});
}
/// <summary>
/// Binarizable entry.
/// </summary>
private class BinarizableEntry
{
/** Value. */
private readonly int _val;
/** <inheritDot /> */
public override int GetHashCode()
{
return _val;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="val">Value.</param>
public BinarizableEntry(int val)
{
_val = val;
}
/** <inheritDoc /> */
public override bool Equals(object obj)
{
var entry = obj as BinarizableEntry;
return entry != null && entry._val == _val;
}
}
/// <summary>
/// Serializable entry.
/// </summary>
[Serializable]
private class SerializableEntry
{
/** Value. */
private readonly int _val;
/** <inheritDot /> */
public override int GetHashCode()
{
return _val;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="val">Value.</param>
public SerializableEntry(int val)
{
_val = val;
}
/** <inheritDoc /> */
public override bool Equals(object obj)
{
var entry = obj as SerializableEntry;
return entry != null && entry._val == _val;
}
}
}
}