| /* |
| * 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; |
| } |
| } |
| } |
| } |