http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/EventsTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/EventsTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/EventsTest.cs new file mode 100644 index 0000000..39b6b24 --- /dev/null +++ b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/EventsTest.cs @@ -0,0 +1,961 @@ +/* + * 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.Linq; + using System.Threading; + using System.Threading.Tasks; + using Apache.Ignite.Core.Cache.Query; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Events; + using Apache.Ignite.Core.Impl; + using Apache.Ignite.Core.Impl.Events; + using Apache.Ignite.Core.Portable; + using Apache.Ignite.Core.Tests.Compute; + using NUnit.Framework; + + /// <summary> + /// <see cref="IEvents"/> tests. + /// </summary> + public class EventsTest + { + /** */ + private IIgnite _grid1; + + /** */ + private IIgnite _grid2; + + /** */ + private IIgnite _grid3; + + /** */ + private IIgnite[] _grids; + + /** */ + public static int IdGen; + + [TestFixtureTearDown] + public void FixtureTearDown() + { + StopGrids(); + } + + /// <summary> + /// Executes before each test. + /// </summary> + [SetUp] + public void SetUp() + { + StartGrids(); + EventsTestHelper.ListenResult = true; + } + + /// <summary> + /// Executes after each test. + /// </summary> + [TearDown] + public virtual void TearDown() + { + try + { + TestUtils.AssertHandleRegistryIsEmpty(1000, _grid1, _grid2, _grid3); + } + catch (Exception) + { + // Restart grids to cleanup + StopGrids(); + + throw; + } + finally + { + EventsTestHelper.AssertFailures(); + + if (TestContext.CurrentContext.Test.Name.StartsWith("TestEventTypes")) + StopGrids(); // clean events for other tests + } + } + + /// <summary> + /// Tests enable/disable of event types. + /// </summary> + [Test] + public void TestEnableDisable() + { + var events = _grid1.Events(); + + Assert.AreEqual(0, events.GetEnabledEvents().Length); + + Assert.IsFalse(EventType.EvtsCache.Any(events.IsEnabled)); + + events.EnableLocal(EventType.EvtsCache); + + Assert.AreEqual(EventType.EvtsCache, events.GetEnabledEvents()); + + Assert.IsTrue(EventType.EvtsCache.All(events.IsEnabled)); + + events.EnableLocal(EventType.EvtsTaskExecution); + + events.DisableLocal(EventType.EvtsCache); + + Assert.AreEqual(EventType.EvtsTaskExecution, events.GetEnabledEvents()); + } + + /// <summary> + /// Tests LocalListen. + /// </summary> + [Test] + public void TestLocalListen() + { + var events = _grid1.Events(); + var listener = EventsTestHelper.GetListener(); + var eventType = EventType.EvtsTaskExecution; + + events.EnableLocal(eventType); + + events.LocalListen(listener, eventType); + + CheckSend(3); // 3 events per task * 3 grids + + // Check unsubscription for specific event + events.StopLocalListen(listener, EventType.EvtTaskReduced); + + CheckSend(2); + + // Unsubscribe from all events + events.StopLocalListen(listener); + + CheckNoEvent(); + + // Check unsubscription by filter + events.LocalListen(listener, EventType.EvtTaskReduced); + + CheckSend(); + + EventsTestHelper.ListenResult = false; + + CheckSend(); // one last event will be received for each listener + + CheckNoEvent(); + } + + /// <summary> + /// Tests LocalListen. + /// </summary> + [Test] + [Ignore("IGNITE-879")] + public void TestLocalListenRepeatedSubscription() + { + var events = _grid1.Events(); + var listener = EventsTestHelper.GetListener(); + var eventType = EventType.EvtsTaskExecution; + + events.EnableLocal(eventType); + + events.LocalListen(listener, eventType); + + CheckSend(3); // 3 events per task * 3 grids + + events.LocalListen(listener, eventType); + events.LocalListen(listener, eventType); + + CheckSend(9); + + events.StopLocalListen(listener, eventType); + + CheckSend(6); + + events.StopLocalListen(listener, eventType); + + CheckSend(3); + + events.StopLocalListen(listener, eventType); + + CheckNoEvent(); + } + + /// <summary> + /// Tests all available event types/classes. + /// </summary> + [Test, TestCaseSource("TestCases")] + public void TestEventTypes(EventTestCase testCase) + { + var events = _grid1.Events(); + + events.EnableLocal(testCase.EventType); + + var listener = EventsTestHelper.GetListener(); + + events.LocalListen(listener, testCase.EventType); + + EventsTestHelper.ClearReceived(testCase.EventCount); + + testCase.GenerateEvent(_grid1); + + EventsTestHelper.VerifyReceive(testCase.EventCount, testCase.EventObjectType, testCase.EventType); + + if (testCase.VerifyEvents != null) + testCase.VerifyEvents(EventsTestHelper.ReceivedEvents.Reverse(), _grid1); + + // Check stop + events.StopLocalListen(listener); + + EventsTestHelper.ClearReceived(0); + + testCase.GenerateEvent(_grid1); + + Thread.Sleep(EventsTestHelper.Timeout); + } + + /// <summary> + /// Test cases for TestEventTypes: type id + type + event generator. + /// </summary> + public IEnumerable<EventTestCase> TestCases + { + get + { + yield return new EventTestCase + { + EventType = EventType.EvtsCache, + EventObjectType = typeof (CacheEvent), + GenerateEvent = g => g.Cache<int, int>(null).Put(1, 1), + VerifyEvents = (e, g) => VerifyCacheEvents(e, g), + EventCount = 1 + }; + + yield return new EventTestCase + { + EventType = EventType.EvtsTaskExecution, + EventObjectType = typeof (TaskEvent), + GenerateEvent = g => GenerateTaskEvent(g), + VerifyEvents = (e, g) => VerifyTaskEvents(e), + EventCount = 3 + }; + + yield return new EventTestCase + { + EventType = EventType.EvtsJobExecution, + EventObjectType = typeof (JobEvent), + GenerateEvent = g => GenerateTaskEvent(g), + EventCount = 9 + }; + + yield return new EventTestCase + { + EventType = new[] {EventType.EvtCacheQueryExecuted}, + EventObjectType = typeof (CacheQueryExecutedEvent), + GenerateEvent = g => GenerateCacheQueryEvent(g), + EventCount = 1 + }; + + yield return new EventTestCase + { + EventType = new[] { EventType.EvtCacheQueryObjectRead }, + EventObjectType = typeof (CacheQueryReadEvent), + GenerateEvent = g => GenerateCacheQueryEvent(g), + EventCount = 1 + }; + } + } + + /// <summary> + /// Tests the LocalQuery. + /// </summary> + [Test] + public void TestLocalQuery() + { + var events = _grid1.Events(); + + var eventType = EventType.EvtsTaskExecution; + + events.EnableLocal(eventType); + + var oldEvents = events.LocalQuery(); + + GenerateTaskEvent(); + + // "Except" works because of overridden equality + var qryResult = events.LocalQuery(eventType).Except(oldEvents).ToList(); + + Assert.AreEqual(3, qryResult.Count); + } + + /// <summary> + /// Tests the WaitForLocal. + /// </summary> + [Test] + public void TestWaitForLocal([Values(true, false)] bool async) + { + var events = _grid1.Events(); + + var timeout = TimeSpan.FromSeconds(3); + + if (async) + events = events.WithAsync(); + + var eventType = EventType.EvtsTaskExecution; + + events.EnableLocal(eventType); + + Func<Func<IEvent>, Task<IEvent>> getWaitTask; + + if (async) + getWaitTask = func => + { + Assert.IsNull(func()); + var task = events.GetFuture<IEvent>().ToTask(); + GenerateTaskEvent(); + return task; + }; + else + getWaitTask = func => + { + var task = Task.Factory.StartNew(func); + Thread.Sleep(500); // allow task to start and begin waiting for events + GenerateTaskEvent(); + return task; + }; + + // No params + var waitTask = getWaitTask(() => events.WaitForLocal()); + + waitTask.Wait(timeout); + + // Event types + waitTask = getWaitTask(() => events.WaitForLocal(EventType.EvtTaskReduced)); + + Assert.IsTrue(waitTask.Wait(timeout)); + Assert.IsInstanceOf(typeof(TaskEvent), waitTask.Result); + Assert.AreEqual(EventType.EvtTaskReduced, waitTask.Result.Type); + + // Filter + waitTask = getWaitTask(() => events.WaitForLocal( + new EventFilter<IEvent>((g, e) => e.Type == EventType.EvtTaskReduced))); + + Assert.IsTrue(waitTask.Wait(timeout)); + Assert.IsInstanceOf(typeof(TaskEvent), waitTask.Result); + Assert.AreEqual(EventType.EvtTaskReduced, waitTask.Result.Type); + + // Filter & types + waitTask = getWaitTask(() => events.WaitForLocal( + new EventFilter<IEvent>((g, e) => e.Type == EventType.EvtTaskReduced), EventType.EvtTaskReduced)); + + Assert.IsTrue(waitTask.Wait(timeout)); + Assert.IsInstanceOf(typeof(TaskEvent), waitTask.Result); + Assert.AreEqual(EventType.EvtTaskReduced, waitTask.Result.Type); + } + + /// <summary> + /// Tests RemoteListen. + /// </summary> + [Test] + public void TestRemoteListen( + [Values(true, false)] bool async, + [Values(true, false)] bool portable, + [Values(true, false)] bool autoUnsubscribe) + { + foreach (var g in _grids) + { + g.Events().EnableLocal(EventType.EvtsJobExecution); + g.Events().EnableLocal(EventType.EvtsTaskExecution); + } + + var events = _grid1.Events(); + + var expectedType = EventType.EvtJobStarted; + + var remoteFilter = portable + ? (IEventFilter<IEvent>) new RemoteEventPortableFilter(expectedType) + : new RemoteEventFilter(expectedType); + + var localListener = EventsTestHelper.GetListener(); + + if (async) + events = events.WithAsync(); + + var listenId = events.RemoteListen(localListener: localListener, remoteFilter: remoteFilter, + autoUnsubscribe: autoUnsubscribe); + + if (async) + listenId = events.GetFuture<Guid>().Get(); + + CheckSend(3, typeof(JobEvent), expectedType); + + _grid3.Events().DisableLocal(EventType.EvtsJobExecution); + + CheckSend(2, typeof(JobEvent), expectedType); + + events.StopRemoteListen(listenId); + + if (async) + events.GetFuture().Get(); + + CheckNoEvent(); + + // Check unsubscription with listener + events.RemoteListen(localListener: localListener, remoteFilter: remoteFilter, + autoUnsubscribe: autoUnsubscribe); + + if (async) + events.GetFuture<Guid>().Get(); + + CheckSend(2, typeof(JobEvent), expectedType); + + EventsTestHelper.ListenResult = false; + + CheckSend(1, typeof(JobEvent), expectedType); // one last event + + CheckNoEvent(); + } + + /// <summary> + /// Tests RemoteQuery. + /// </summary> + [Test] + public void TestRemoteQuery([Values(true, false)] bool async) + { + foreach (var g in _grids) + g.Events().EnableLocal(EventType.EvtsJobExecution); + + var events = _grid1.Events(); + + var eventFilter = new RemoteEventFilter(EventType.EvtJobStarted); + + var oldEvents = events.RemoteQuery(eventFilter); + + if (async) + events = events.WithAsync(); + + GenerateTaskEvent(); + + var remoteQuery = events.RemoteQuery(eventFilter, EventsTestHelper.Timeout, EventType.EvtsJobExecution); + + if (async) + { + Assert.IsNull(remoteQuery); + + remoteQuery = events.GetFuture<List<IEvent>>().Get().ToList(); + } + + var qryResult = remoteQuery.Except(oldEvents).Cast<JobEvent>().ToList(); + + Assert.AreEqual(_grids.Length, qryResult.Count); + + Assert.IsTrue(qryResult.All(x => x.Type == EventType.EvtJobStarted)); + } + + /// <summary> + /// Tests serialization. + /// </summary> + [Test] + public void TestSerialization() + { + var grid = (Ignite) _grid1; + var comp = (Impl.Compute.Compute) grid.Cluster.ForLocal().Compute(); + var locNode = grid.Cluster.LocalNode; + + var expectedGuid = Guid.Parse("00000000-0000-0001-0000-000000000002"); + var expectedGridGuid = new IgniteGuid(expectedGuid, 3); + + using (var inStream = IgniteManager.Memory.Allocate().Stream()) + { + var result = comp.ExecuteJavaTask<bool>("org.apache.ignite.platform.PlatformEventsWriteEventTask", + inStream.MemoryPointer); + + Assert.IsTrue(result); + + inStream.SynchronizeInput(); + + var reader = grid.Marshaller.StartUnmarshal(inStream); + + var cacheEvent = EventReader.Read<CacheEvent>(reader); + CheckEventBase(cacheEvent); + Assert.AreEqual("cacheName", cacheEvent.CacheName); + Assert.AreEqual(locNode, cacheEvent.EventNode); + Assert.AreEqual(1, cacheEvent.Partition); + Assert.AreEqual(true, cacheEvent.IsNear); + Assert.AreEqual(2, cacheEvent.Key); + Assert.AreEqual(expectedGridGuid, cacheEvent.Xid); + Assert.AreEqual(3, cacheEvent.LockId); + Assert.AreEqual(4, cacheEvent.NewValue); + Assert.AreEqual(true, cacheEvent.HasNewValue); + Assert.AreEqual(5, cacheEvent.OldValue); + Assert.AreEqual(true, cacheEvent.HasOldValue); + Assert.AreEqual(expectedGuid, cacheEvent.SubjectId); + Assert.AreEqual("cloClsName", cacheEvent.ClosureClassName); + Assert.AreEqual("taskName", cacheEvent.TaskName); + + var qryExecEvent = EventReader.Read<CacheQueryExecutedEvent>(reader); + CheckEventBase(qryExecEvent); + Assert.AreEqual("qryType", qryExecEvent.QueryType); + Assert.AreEqual("cacheName", qryExecEvent.CacheName); + Assert.AreEqual("clsName", qryExecEvent.ClassName); + Assert.AreEqual("clause", qryExecEvent.Clause); + Assert.AreEqual(expectedGuid, qryExecEvent.SubjectId); + Assert.AreEqual("taskName", qryExecEvent.TaskName); + + var qryReadEvent = EventReader.Read<CacheQueryReadEvent>(reader); + CheckEventBase(qryReadEvent); + Assert.AreEqual("qryType", qryReadEvent.QueryType); + Assert.AreEqual("cacheName", qryReadEvent.CacheName); + Assert.AreEqual("clsName", qryReadEvent.ClassName); + Assert.AreEqual("clause", qryReadEvent.Clause); + Assert.AreEqual(expectedGuid, qryReadEvent.SubjectId); + Assert.AreEqual("taskName", qryReadEvent.TaskName); + Assert.AreEqual(1, qryReadEvent.Key); + Assert.AreEqual(2, qryReadEvent.Value); + Assert.AreEqual(3, qryReadEvent.OldValue); + Assert.AreEqual(4, qryReadEvent.Row); + + var cacheRebalancingEvent = EventReader.Read<CacheRebalancingEvent>(reader); + CheckEventBase(cacheRebalancingEvent); + Assert.AreEqual("cacheName", cacheRebalancingEvent.CacheName); + Assert.AreEqual(1, cacheRebalancingEvent.Partition); + Assert.AreEqual(locNode, cacheRebalancingEvent.DiscoveryNode); + Assert.AreEqual(2, cacheRebalancingEvent.DiscoveryEventType); + Assert.AreEqual(3, cacheRebalancingEvent.DiscoveryTimestamp); + + var checkpointEvent = EventReader.Read<CheckpointEvent>(reader); + CheckEventBase(checkpointEvent); + Assert.AreEqual("cpKey", checkpointEvent.Key); + + var discoEvent = EventReader.Read<DiscoveryEvent>(reader); + CheckEventBase(discoEvent); + Assert.AreEqual(grid.TopologyVersion, discoEvent.TopologyVersion); + Assert.AreEqual(grid.Nodes(), discoEvent.TopologyNodes); + + var jobEvent = EventReader.Read<JobEvent>(reader); + CheckEventBase(jobEvent); + Assert.AreEqual(expectedGridGuid, jobEvent.JobId); + Assert.AreEqual("taskClsName", jobEvent.TaskClassName); + Assert.AreEqual("taskName", jobEvent.TaskName); + Assert.AreEqual(locNode, jobEvent.TaskNode); + Assert.AreEqual(expectedGridGuid, jobEvent.TaskSessionId); + Assert.AreEqual(expectedGuid, jobEvent.TaskSubjectId); + + var spaceEvent = EventReader.Read<SwapSpaceEvent>(reader); + CheckEventBase(spaceEvent); + Assert.AreEqual("space", spaceEvent.Space); + + var taskEvent = EventReader.Read<TaskEvent>(reader); + CheckEventBase(taskEvent); + Assert.AreEqual(true,taskEvent.Internal); + Assert.AreEqual(expectedGuid, taskEvent.SubjectId); + Assert.AreEqual("taskClsName", taskEvent.TaskClassName); + Assert.AreEqual("taskName", taskEvent.TaskName); + Assert.AreEqual(expectedGridGuid, taskEvent.TaskSessionId); + } + } + + /// <summary> + /// Checks base event fields serialization. + /// </summary> + /// <param name="evt">The evt.</param> + private void CheckEventBase(IEvent evt) + { + var locNode = _grid1.Cluster.LocalNode; + + Assert.AreEqual(locNode, evt.Node); + Assert.AreEqual("msg", evt.Message); + Assert.AreEqual(EventType.EvtSwapSpaceCleared, evt.Type); + Assert.IsNotNullOrEmpty(evt.Name); + Assert.AreNotEqual(Guid.Empty, evt.Id.GlobalId); + Assert.IsTrue((evt.TimeStamp - DateTime.Now).TotalSeconds < 10); + } + + /// <summary> + /// Sends events in various ways and verifies correct receive. + /// </summary> + /// <param name="repeat">Expected event count multiplier.</param> + /// <param name="eventObjectType">Expected event object type.</param> + /// <param name="eventType">Type of the event.</param> + private void CheckSend(int repeat = 1, Type eventObjectType = null, params int[] eventType) + { + EventsTestHelper.ClearReceived(repeat); + + GenerateTaskEvent(); + + EventsTestHelper.VerifyReceive(repeat, eventObjectType ?? typeof (TaskEvent), + eventType.Any() ? eventType : EventType.EvtsTaskExecution); + } + + /// <summary> + /// Checks that no event has arrived. + /// </summary> + private void CheckNoEvent() + { + // this will result in an exception in case of a event + EventsTestHelper.ClearReceived(0); + + GenerateTaskEvent(); + + Thread.Sleep(EventsTestHelper.Timeout); + + EventsTestHelper.AssertFailures(); + } + + /// <summary> + /// Gets the Ignite configuration. + /// </summary> + private static IgniteConfiguration Configuration(string springConfigUrl) + { + return new IgniteConfiguration + { + SpringConfigUrl = springConfigUrl, + JvmClasspath = TestUtils.CreateTestClasspath(), + JvmOptions = TestUtils.TestJavaOptions(), + PortableConfiguration = new PortableConfiguration + { + TypeConfigurations = new List<PortableTypeConfiguration> + { + new PortableTypeConfiguration(typeof (RemoteEventPortableFilter)) + } + } + }; + } + + /// <summary> + /// Generates the task event. + /// </summary> + private void GenerateTaskEvent(IIgnite grid = null) + { + (grid ?? _grid1).Compute().Broadcast(new ComputeAction()); + } + + /// <summary> + /// Verifies the task events. + /// </summary> + private static void VerifyTaskEvents(IEnumerable<IEvent> events) + { + var e = events.Cast<TaskEvent>().ToArray(); + + // started, reduced, finished + Assert.AreEqual( + new[] {EventType.EvtTaskStarted, EventType.EvtTaskReduced, EventType.EvtTaskFinished}, + e.Select(x => x.Type).ToArray()); + } + + /// <summary> + /// Generates the cache query event. + /// </summary> + private static void GenerateCacheQueryEvent(IIgnite g) + { + var cache = g.Cache<int, int>(null); + + cache.Clear(); + + cache.Put(1, 1); + + cache.Query(new ScanQuery<int, int>()).GetAll(); + } + + /// <summary> + /// Verifies the cache events. + /// </summary> + private static void VerifyCacheEvents(IEnumerable<IEvent> events, IIgnite grid) + { + var e = events.Cast<CacheEvent>().ToArray(); + + foreach (var cacheEvent in e) + { + Assert.AreEqual(null, cacheEvent.CacheName); + Assert.AreEqual(null, cacheEvent.ClosureClassName); + Assert.AreEqual(null, cacheEvent.TaskName); + Assert.AreEqual(grid.Cluster.LocalNode, cacheEvent.EventNode); + Assert.AreEqual(grid.Cluster.LocalNode, cacheEvent.Node); + + Assert.AreEqual(false, cacheEvent.HasOldValue); + Assert.AreEqual(null, cacheEvent.OldValue); + + if (cacheEvent.Type == EventType.EvtCacheObjectPut) + { + Assert.AreEqual(true, cacheEvent.HasNewValue); + Assert.AreEqual(1, cacheEvent.NewValue); + } + else if (cacheEvent.Type == EventType.EvtCacheEntryCreated) + { + Assert.AreEqual(false, cacheEvent.HasNewValue); + Assert.AreEqual(null, cacheEvent.NewValue); + } + else + { + Assert.Fail("Unexpected event type"); + } + } + } + + /// <summary> + /// Starts the grids. + /// </summary> + private void StartGrids() + { + if (_grid1 != null) + return; + + _grid1 = Ignition.Start(Configuration("config\\compute\\compute-grid1.xml")); + _grid2 = Ignition.Start(Configuration("config\\compute\\compute-grid2.xml")); + _grid3 = Ignition.Start(Configuration("config\\compute\\compute-grid3.xml")); + + _grids = new[] {_grid1, _grid2, _grid3}; + } + + /// <summary> + /// Stops the grids. + /// </summary> + private void StopGrids() + { + _grid1 = _grid2 = _grid3 = null; + _grids = null; + + Ignition.StopAll(true); + } + } + + /// <summary> + /// Event test helper class. + /// </summary> + [Serializable] + public static class EventsTestHelper + { + /** */ + public static readonly ConcurrentStack<IEvent> ReceivedEvents = new ConcurrentStack<IEvent>(); + + /** */ + public static readonly ConcurrentStack<string> Failures = new ConcurrentStack<string>(); + + /** */ + public static readonly CountdownEvent ReceivedEvent = new CountdownEvent(0); + + /** */ + public static readonly ConcurrentStack<Guid> LastNodeIds = new ConcurrentStack<Guid>(); + + /** */ + public static volatile bool ListenResult = true; + + /** */ + public static readonly TimeSpan Timeout = TimeSpan.FromMilliseconds(800); + + /// <summary> + /// Clears received event information. + /// </summary> + /// <param name="expectedCount">The expected count of events to be received.</param> + public static void ClearReceived(int expectedCount) + { + ReceivedEvents.Clear(); + ReceivedEvent.Reset(expectedCount); + LastNodeIds.Clear(); + } + + /// <summary> + /// Verifies received events against events events. + /// </summary> + public static void VerifyReceive(int count, Type eventObjectType, params int[] eventTypes) + { + // check if expected event count has been received; Wait returns false if there were none. + Assert.IsTrue(ReceivedEvent.Wait(Timeout), + "Failed to receive expected number of events. Remaining count: " + ReceivedEvent.CurrentCount); + + Assert.AreEqual(count, ReceivedEvents.Count); + + Assert.IsTrue(ReceivedEvents.All(x => x.GetType() == eventObjectType)); + + Assert.IsTrue(ReceivedEvents.All(x => eventTypes.Contains(x.Type))); + + AssertFailures(); + } + + /// <summary> + /// Gets the event listener. + /// </summary> + /// <returns>New instance of event listener.</returns> + public static IEventFilter<IEvent> GetListener() + { + return new EventFilter<IEvent>(Listen); + } + + /// <summary> + /// Combines accumulated failures and throws an assertion, if there are any. + /// Clears accumulated failures. + /// </summary> + public static void AssertFailures() + { + try + { + if (Failures.Any()) + Assert.Fail(Failures.Reverse().Aggregate((x, y) => string.Format("{0}\n{1}", x, y))); + } + finally + { + Failures.Clear(); + } + } + + /// <summary> + /// Listen method. + /// </summary> + /// <param name="id">Originating node ID.</param> + /// <param name="evt">Event.</param> + private static bool Listen(Guid id, IEvent evt) + { + try + { + LastNodeIds.Push(id); + ReceivedEvents.Push(evt); + + ReceivedEvent.Signal(); + + return ListenResult; + } + catch (Exception ex) + { + // When executed on remote nodes, these exceptions will not go to sender, + // so we have to accumulate them. + Failures.Push(string.Format("Exception in Listen (msg: {0}, id: {1}): {2}", evt, id, ex)); + throw; + } + } + } + + /// <summary> + /// Test event filter. + /// </summary> + [Serializable] + public class EventFilter<T> : IEventFilter<T> where T : IEvent + { + /** */ + private readonly Func<Guid, T, bool> _invoke; + + /// <summary> + /// Initializes a new instance of the <see cref="RemoteListenEventFilter"/> class. + /// </summary> + /// <param name="invoke">The invoke delegate.</param> + public EventFilter(Func<Guid, T, bool> invoke) + { + _invoke = invoke; + } + + /** <inheritdoc /> */ + bool IEventFilter<T>.Invoke(Guid nodeId, T evt) + { + return _invoke(nodeId, evt); + } + + /** <inheritdoc /> */ + public bool Invoke(Guid nodeId, T evt) + { + throw new Exception("Invalid method"); + } + } + + /// <summary> + /// Remote event filter. + /// </summary> + [Serializable] + public class RemoteEventFilter : IEventFilter<IEvent> + { + /** */ + private readonly int _type; + + public RemoteEventFilter(int type) + { + _type = type; + } + + /** <inheritdoc /> */ + public bool Invoke(Guid nodeId, IEvent evt) + { + return evt.Type == _type; + } + } + + /// <summary> + /// Portable remote event filter. + /// </summary> + public class RemoteEventPortableFilter : IEventFilter<IEvent>, IPortableMarshalAware + { + /** */ + private int _type; + + /// <summary> + /// Initializes a new instance of the <see cref="RemoteEventPortableFilter"/> class. + /// </summary> + /// <param name="type">The event type.</param> + public RemoteEventPortableFilter(int type) + { + _type = type; + } + + /** <inheritdoc /> */ + public bool Invoke(Guid nodeId, IEvent evt) + { + return evt.Type == _type; + } + + /** <inheritdoc /> */ + public void WritePortable(IPortableWriter writer) + { + writer.RawWriter().WriteInt(_type); + } + + /** <inheritdoc /> */ + public void ReadPortable(IPortableReader reader) + { + _type = reader.RawReader().ReadInt(); + } + } + + /// <summary> + /// Event test case. + /// </summary> + public class EventTestCase + { + /// <summary> + /// Gets or sets the type of the event. + /// </summary> + public int[] EventType { get; set; } + + /// <summary> + /// Gets or sets the type of the event object. + /// </summary> + public Type EventObjectType { get; set; } + + /// <summary> + /// Gets or sets the generate event action. + /// </summary> + public Action<IIgnite> GenerateEvent { get; set; } + + /// <summary> + /// Gets or sets the verify events action. + /// </summary> + public Action<IEnumerable<IEvent>, IIgnite> VerifyEvents { get; set; } + + /// <summary> + /// Gets or sets the event count. + /// </summary> + public int EventCount { get; set; } + + /** <inheritdoc /> */ + public override string ToString() + { + return EventObjectType.ToString(); + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs new file mode 100644 index 0000000..d90067f --- /dev/null +++ b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs @@ -0,0 +1,352 @@ +/* + * 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.IO; + using System.Linq; + using System.Runtime.Serialization.Formatters.Binary; + using System.Threading.Tasks; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl; + using Apache.Ignite.Core.Portable; + using NUnit.Framework; + + /// <summary> + /// Tests grid exceptions propagation. + /// </summary> + public class ExceptionsTest + { + /// <summary> + /// Before test. + /// </summary> + [SetUp] + public void SetUp() + { + TestUtils.KillProcesses(); + } + + /// <summary> + /// After test. + /// </summary> + [TearDown] + public void TearDown() + { + Ignition.StopAll(true); + } + + /// <summary> + /// Tests exceptions. + /// </summary> + [Test] + public void TestExceptions() + { + var grid = StartGrid(); + + try + { + grid.Cache<object, object>("invalidCacheName"); + + Assert.Fail(); + } + catch (Exception e) + { + Assert.IsTrue(e is ArgumentException); + } + + try + { + grid.Cluster.ForRemotes().Metrics(); + + Assert.Fail(); + } + catch (Exception e) + { + Assert.IsTrue(e is ClusterGroupEmptyException); + } + + grid.Dispose(); + + try + { + grid.Cache<object, object>("cache1"); + + Assert.Fail(); + } + catch (Exception e) + { + Assert.IsTrue(e is InvalidOperationException); + } + } + + /// <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 PortableEntry(x)); + } + + /// <summary> + /// Tests CachePartialUpdateException keys propagation in portable mode. + /// </summary> + [Test] + [Category(TestUtils.CategoryIntensive)] + public void TestPartialUpdateExceptionPortable() + { + // User type + TestPartialUpdateException(false, (x, g) => g.Portables().ToPortable<IPortableObject>(new PortableEntry(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 CachePartialUpdateException serialization. + /// </summary> + private static void TestPartialUpdateExceptionSerialization(Exception ex) + { + var formatter = new BinaryFormatter(); + + var stream = new MemoryStream(); + + formatter.Serialize(stream, ex); + + stream.Seek(0, SeekOrigin.Begin); + + var ex0 = (Exception) formatter.Deserialize(stream); + + 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 PortableEntry(x)); + } + + /// <summary> + /// Tests CachePartialUpdateException keys propagation in portable mode. + /// </summary> + [Test] + [Category(TestUtils.CategoryIntensive)] + public void TestPartialUpdateExceptionAsyncPortable() + { + TestPartialUpdateException(true, (x, g) => g.Portables().ToPortable<IPortableObject>(new PortableEntry(x))); + } + + /// <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.Cache<TK, int>("partitioned_atomic").WithNoRetries(); + + if (async) + cache = cache.WithAsync(); + + if (typeof (TK) == typeof (IPortableObject)) + cache = cache.WithKeepPortable<TK, int>(); + + // Do cache puts in parallel + var putTask = Task.Factory.StartNew(() => + { + try + { + // Do a lot of puts so that one fails during Ignite stop + for (var i = 0; i < 1000000; i++) + { + cache.PutAll(Enumerable.Range(1, 100).ToDictionary(k => keyFunc(k, grid), k => i)); + + if (async) + cache.GetFuture().Get(); + } + } + catch (CachePartialUpdateException ex) + { + var failedKeys = ex.GetFailedKeys<TK>(); + + Assert.IsTrue(failedKeys.Any()); + + var failedKeysObj = ex.GetFailedKeys<object>(); + + Assert.IsTrue(failedKeysObj.Any()); + + return; + } + + Assert.Fail("CachePartialUpdateException has not been thrown."); + }); + + while (true) + { + Ignition.Stop("grid_2", true); + StartGrid("grid_2"); + + if (putTask.Exception != null) + throw putTask.Exception; + + if (putTask.IsCompleted) + return; + } + } + } + + /// <summary> + /// Starts the grid. + /// </summary> + private static IIgnite StartGrid(string gridName = null) + { + return Ignition.Start(new IgniteConfigurationEx + { + SpringConfigUrl = "config\\native-client-test-cache.xml", + JvmOptions = TestUtils.TestJavaOptions(), + JvmClasspath = TestUtils.CreateTestClasspath(), + GridName = gridName, + PortableConfiguration = new PortableConfiguration + { + TypeConfigurations = new[] + { + new PortableTypeConfiguration(typeof (PortableEntry)) + } + } + }); + } + + /// <summary> + /// Portable entry. + /// </summary> + private class PortableEntry + { + /** Value. */ + private readonly int _val; + + /** <inheritDot /> */ + public override int GetHashCode() + { + return _val; + } + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="val">Value.</param> + public PortableEntry(int val) + { + _val = val; + } + + /** <inheritDoc /> */ + public override bool Equals(object obj) + { + return obj is PortableEntry && ((PortableEntry)obj)._val == _val; + } + } + + /// <summary> + /// Portable 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) + { + return obj is SerializableEntry && ((SerializableEntry)obj)._val == _val; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs new file mode 100644 index 0000000..9c47cbc --- /dev/null +++ b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/ExecutableTest.cs @@ -0,0 +1,444 @@ +/* + * 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. + */ + +// ReSharper disable UnusedVariable +// ReSharper disable UnusedAutoPropertyAccessor.Global +namespace Apache.Ignite.Core.Tests +{ + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using Apache.Ignite.Core.Compute; + using Apache.Ignite.Core.Impl; + using Apache.Ignite.Core.Portable; + using Apache.Ignite.Core.Resource; + using Apache.Ignite.Core.Tests.Process; + using Microsoft.CSharp; + using NUnit.Framework; + + /// <summary> + /// Tests for executable. + /// </summary> + [Ignore("IGNITE-1367")] + public class ExecutableTest + { + /** Spring configuration path. */ + private static readonly string SpringCfgPath = "config\\compute\\compute-standalone.xml"; + + /** Min memory Java task. */ + private const string MinMemTask = "org.apache.ignite.platform.PlatformMinMemoryTask"; + + /** Max memory Java task. */ + private const string MaxMemTask = "org.apache.ignite.platform.PlatformMaxMemoryTask"; + + /** Grid. */ + private IIgnite _grid; + + /// <summary> + /// Test fixture set-up routine. + /// </summary> + [TestFixtureSetUp] + public void TestFixtureSetUp() + { + TestUtils.KillProcesses(); + + _grid = Ignition.Start(Configuration(SpringCfgPath)); + } + + /// <summary> + /// Test fixture tear-down routine. + /// </summary> + [TestFixtureTearDown] + public void TestFixtureTearDown() + { + Ignition.StopAll(true); + + TestUtils.KillProcesses(); + } + + /// <summary> + /// Set-up routine. + /// </summary> + [SetUp] + public void SetUp() + { + TestUtils.KillProcesses(); + + Assert.IsTrue(_grid.WaitTopology(1, 30000)); + + IgniteProcess.SaveConfigurationBackup(); + } + + /// <summary> + /// Tear-down routine. + /// </summary> + [TearDown] + public void TearDown() + { + IgniteProcess.RestoreConfigurationBackup(); + } + + /// <summary> + /// Test data pass through configuration file. + /// </summary> + [Test] + public void TestConfig() + { + IgniteProcess.ReplaceConfiguration("config\\Ignite.exe.config.test"); + + GenerateDll("test-1.dll"); + GenerateDll("test-2.dll"); + + IgniteProcess proc = new IgniteProcess( + "-jvmClasspath=" + TestUtils.CreateTestClasspath() + ); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + RemoteConfiguration cfg = RemoteConfig(); + + Assert.AreEqual(SpringCfgPath, cfg.SpringConfigUrl); + Assert.IsTrue(cfg.JvmOptions.Contains("-DOPT1") && cfg.JvmOptions.Contains("-DOPT2")); + Assert.IsTrue(cfg.Assemblies.Contains("test-1.dll") && cfg.Assemblies.Contains("test-2.dll")); + Assert.AreEqual(601, cfg.JvmInitialMemoryMb); + Assert.AreEqual(702, cfg.JvmMaxMemoryMb); + } + + /// <summary> + /// Test assemblies passing through command-line. + /// </summary> + [Test] + public void TestAssemblyCmd() + { + GenerateDll("test-1.dll"); + GenerateDll("test-2.dll"); + + IgniteProcess proc = new IgniteProcess( + "-jvmClasspath=" + TestUtils.CreateTestClasspath(), + "-springConfigUrl=" + SpringCfgPath, + "-assembly=test-1.dll", + "-assembly=test-2.dll" + ); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + RemoteConfiguration cfg = RemoteConfig(); + + Assert.IsTrue(cfg.Assemblies.Contains("test-1.dll") && cfg.Assemblies.Contains("test-2.dll")); + } + + /// <summary> + /// Test JVM options passing through command-line. + /// </summary> + [Test] + public void TestJvmOptsCmd() + { + IgniteProcess proc = new IgniteProcess( + "-jvmClasspath=" + TestUtils.CreateTestClasspath(), + "-springConfigUrl=" + SpringCfgPath, + "-J-DOPT1", + "-J-DOPT2" + ); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + RemoteConfiguration cfg = RemoteConfig(); + + Assert.IsTrue(cfg.JvmOptions.Contains("-DOPT1") && cfg.JvmOptions.Contains("-DOPT2")); + } + + /// <summary> + /// Test JVM memory options passing through command-line: raw java options. + /// </summary> + [Test] + public void TestJvmMemoryOptsCmdRaw() + { + var proc = new IgniteProcess( + "-jvmClasspath=" + TestUtils.CreateTestClasspath(), + "-springConfigUrl=" + SpringCfgPath, + "-J-Xms506m", + "-J-Xmx607m" + ); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + var minMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MinMemTask, null); + Assert.AreEqual((long) 506*1024*1024, minMem); + + var maxMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MaxMemTask, null); + AssertJvmMaxMemory((long) 607*1024*1024, maxMem); + } + + /// <summary> + /// Test JVM memory options passing through command-line: custom options. + /// </summary> + [Test] + public void TestJvmMemoryOptsCmdCustom() + { + var proc = new IgniteProcess( + "-jvmClasspath=" + TestUtils.CreateTestClasspath(), + "-springConfigUrl=" + SpringCfgPath, + "-JvmInitialMemoryMB=615", + "-JvmMaxMemoryMB=863" + ); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + var minMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MinMemTask, null); + Assert.AreEqual((long) 615*1024*1024, minMem); + + var maxMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MaxMemTask, null); + AssertJvmMaxMemory((long) 863*1024*1024, maxMem); + } + + /// <summary> + /// Test JVM memory options passing from application configuration. + /// </summary> + [Test] + public void TestJvmMemoryOptsAppConfig() + { + IgniteProcess.ReplaceConfiguration("config\\Ignite.exe.config.test"); + + GenerateDll("test-1.dll"); + GenerateDll("test-2.dll"); + + var proc = new IgniteProcess("-jvmClasspath=" + TestUtils.CreateTestClasspath()); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + var minMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MinMemTask, null); + Assert.AreEqual((long) 601*1024*1024, minMem); + + var maxMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MaxMemTask, null); + AssertJvmMaxMemory((long) 702*1024*1024, maxMem); + + proc.Kill(); + + Assert.IsTrue(_grid.WaitTopology(1, 30000)); + + // Command line options overwrite config file options + // ReSharper disable once RedundantAssignment + proc = new IgniteProcess("-jvmClasspath=" + TestUtils.CreateTestClasspath(), + "-J-Xms605m", "-J-Xmx706m"); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + minMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MinMemTask, null); + Assert.AreEqual((long) 605*1024*1024, minMem); + + maxMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MaxMemTask, null); + AssertJvmMaxMemory((long) 706*1024*1024, maxMem); + } + + /// <summary> + /// Test JVM memory options passing through command-line: custom options + raw options. + /// </summary> + [Test] + public void TestJvmMemoryOptsCmdCombined() + { + var proc = new IgniteProcess( + "-jvmClasspath=" + TestUtils.CreateTestClasspath(), + "-springConfigUrl=" + SpringCfgPath, + "-J-Xms555m", + "-J-Xmx666m", + "-JvmInitialMemoryMB=128", + "-JvmMaxMemoryMB=256" + ); + + Assert.IsTrue(_grid.WaitTopology(2, 30000)); + + // Raw JVM options (Xms/Xmx) should override custom options + var minMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MinMemTask, null); + Assert.AreEqual((long) 555*1024*1024, minMem); + + var maxMem = _grid.Cluster.ForRemotes().Compute().ExecuteJavaTask<long>(MaxMemTask, null); + AssertJvmMaxMemory((long) 666*1024*1024, maxMem); + } + + /// <summary> + /// Get remote node configuration. + /// </summary> + /// <returns>Configuration.</returns> + private RemoteConfiguration RemoteConfig() + { + return _grid.Cluster.ForRemotes().Compute().Call(new RemoteConfigurationClosure()); + } + + /// <summary> + /// Configuration for node. + /// </summary> + /// <param name="path">Path to Java XML configuration.</param> + /// <returns>Node configuration.</returns> + private static IgniteConfiguration Configuration(string path) + { + IgniteConfiguration cfg = new IgniteConfiguration(); + + + PortableConfiguration portCfg = new PortableConfiguration(); + + ICollection<PortableTypeConfiguration> portTypeCfgs = new List<PortableTypeConfiguration>(); + + portTypeCfgs.Add(new PortableTypeConfiguration(typeof (RemoteConfiguration))); + portTypeCfgs.Add(new PortableTypeConfiguration(typeof (RemoteConfigurationClosure))); + + portCfg.TypeConfigurations = portTypeCfgs; + + cfg.PortableConfiguration = portCfg; + + cfg.JvmClasspath = TestUtils.CreateTestClasspath(); + + cfg.JvmOptions = new List<string> + { + "-ea", + "-Xcheck:jni", + "-Xms4g", + "-Xmx4g", + "-DGRIDGAIN_QUIET=false", + "-Xnoagent", + "-Djava.compiler=NONE", + "-Xdebug", + "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005", + "-XX:+HeapDumpOnOutOfMemoryError" + }; + + cfg.SpringConfigUrl = path; + + return cfg; + } + + /// <summary> + /// + /// </summary> + /// <param name="outputPath"></param> + private static void GenerateDll(string outputPath) + { + CSharpCodeProvider codeProvider = new CSharpCodeProvider(); + +#pragma warning disable 0618 + + ICodeCompiler icc = codeProvider.CreateCompiler(); + +#pragma warning restore 0618 + + CompilerParameters parameters = new CompilerParameters(); + parameters.GenerateExecutable = false; + parameters.OutputAssembly = outputPath; + + string src = "namespace GridGain.Client.Test { public class Foo {}}"; + + CompilerResults results = icc.CompileAssemblyFromSource(parameters, src); + + Assert.False(results.Errors.HasErrors); + } + + /// <summary> + /// Asserts that JVM maximum memory corresponds to Xmx parameter value. + /// </summary> + private static void AssertJvmMaxMemory(long expected, long actual) + { + // allow 20% tolerance because max memory in Java is not exactly equal to Xmx parameter value + Assert.LessOrEqual(actual, expected); + Assert.Greater(actual, expected/5*4); + } + + /// <summary> + /// Closure which extracts configuration and passes it back. + /// </summary> + public class RemoteConfigurationClosure : IComputeFunc<RemoteConfiguration> + { + +#pragma warning disable 0649 + + /** Grid. */ + [InstanceResource] private IIgnite _grid; + +#pragma warning restore 0649 + + /** <inheritDoc /> */ + + public RemoteConfiguration Invoke() + { + Ignite grid0 = (Ignite) ((IgniteProxy) _grid).Target; + + IgniteConfiguration cfg = grid0.Configuration; + + RemoteConfiguration res = new RemoteConfiguration + { + IgniteHome = cfg.IgniteHome, + SpringConfigUrl = cfg.SpringConfigUrl, + JvmDll = cfg.JvmDllPath, + JvmClasspath = cfg.JvmClasspath, + JvmOptions = cfg.JvmOptions, + Assemblies = cfg.Assemblies, + JvmInitialMemoryMb = cfg.JvmInitialMemoryMb, + JvmMaxMemoryMb = cfg.JvmMaxMemoryMb + }; + + Console.WriteLine("RETURNING CFG: " + cfg); + + return res; + } + } + + /// <summary> + /// Configuration. + /// </summary> + public class RemoteConfiguration + { + /// <summary> + /// GG home. + /// </summary> + public string IgniteHome { get; set; } + + /// <summary> + /// Spring config URL. + /// </summary> + public string SpringConfigUrl { get; set; } + + /// <summary> + /// JVM DLL. + /// </summary> + public string JvmDll { get; set; } + + /// <summary> + /// JVM classpath. + /// </summary> + public string JvmClasspath { get; set; } + + /// <summary> + /// JVM options. + /// </summary> + public ICollection<string> JvmOptions { get; set; } + + /// <summary> + /// Assemblies. + /// </summary> + public ICollection<string> Assemblies { get; set; } + + /// <summary> + /// Minimum JVM memory (Xms). + /// </summary> + public int JvmInitialMemoryMb { get; set; } + + /// <summary> + /// Maximum JVM memory (Xms). + /// </summary> + public int JvmMaxMemoryMb { get; set; } + + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs new file mode 100644 index 0000000..c2815db --- /dev/null +++ b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/FutureTest.cs @@ -0,0 +1,278 @@ +/* + * 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.Generic; + using System.Threading; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Compute; + using Apache.Ignite.Core.Portable; + using NUnit.Framework; + + /// <summary> + /// Future tests. + /// </summary> + public class FutureTest + { + /** */ + private ICache<object, object> _cache; + + /** */ + private ICompute _compute; + + /// <summary> + /// Test fixture set-up routine. + /// </summary> + [TestFixtureSetUp] + public void TestFixtureSetUp() + { + TestUtils.KillProcesses(); + + var grid = Ignition.Start(new IgniteConfiguration + { + SpringConfigUrl = "config\\compute\\compute-standalone.xml", + JvmClasspath = TestUtils.CreateTestClasspath(), + JvmOptions = TestUtils.TestJavaOptions(), + PortableConfiguration = new PortableConfiguration + { + TypeConfigurations = + new List<PortableTypeConfiguration> { new PortableTypeConfiguration(typeof(Portable)) } + } + }); + + _cache = grid.Cache<object, object>(null).WithAsync(); + + _compute = grid.Compute().WithAsync(); + } + + /// <summary> + /// Test fixture tear-down routine. + /// </summary> + [TestFixtureTearDown] + public void TestFixtureTearDown() + { + TestUtils.KillProcesses(); + } + + [Test] + public void TestListen() + { + // Listen(Action callback) + TestListen((fut, act) => fut.Listen(act)); + + // Listen(Action<IFuture> callback) + TestListen((fut, act) => ((IFuture)fut).Listen(f => + { + Assert.AreEqual(f, fut); + act(); + })); + + // Listen(Action<IFuture<T>> callback) + TestListen((fut, act) => fut.Listen(f => + { + Assert.AreEqual(f, fut); + act(); + })); + } + + private void TestListen(Action<IFuture<object>, Action> listenAction) + { + _compute.Broadcast(new SleepAction()); + + var fut = _compute.GetFuture<object>(); + + var listenCount = 0; + + // Multiple subscribers before completion + for (var i = 0; i < 10; i++) + listenAction(fut, () => Interlocked.Increment(ref listenCount)); + + Assert.IsFalse(fut.IsDone); + + Assert.IsNull(fut.Get()); + + Thread.Sleep(100); // wait for future completion thread + + Assert.AreEqual(10, listenCount); + + // Multiple subscribers after completion + for (var i = 0; i < 10; i++) + listenAction(fut, () => Interlocked.Decrement(ref listenCount)); + + Assert.AreEqual(0, listenCount); + } + + [Test] + public void TestToTask() + { + _cache.Put(1, 1); + + _cache.GetFuture().ToTask().Wait(); + + _cache.Get(1); + + var task1 = _cache.GetFuture<int>().ToTask(); + + Assert.AreEqual(1, task1.Result); + + Assert.IsTrue(task1.IsCompleted); + + _compute.Broadcast(new SleepAction()); + + var task2 = _compute.GetFuture().ToTask(); + + Assert.IsFalse(task2.IsCompleted); + + Assert.IsFalse(task2.Wait(100)); + + task2.Wait(); + + Assert.IsTrue(task2.IsCompleted); + + Assert.AreEqual(null, task2.Result); + } + + [Test] + public void TestGetWithTimeout() + { + _compute.Broadcast(new SleepAction()); + + var fut = _compute.GetFuture(); + + Assert.Throws<TimeoutException>(() => fut.Get(TimeSpan.FromMilliseconds(100))); + + fut.Get(TimeSpan.FromSeconds(1)); + + Assert.IsTrue(fut.IsDone); + } + + [Test] + public void TestToAsyncResult() + { + _compute.Broadcast(new SleepAction()); + + IFuture fut = _compute.GetFuture(); + + var asyncRes = fut.ToAsyncResult(); + + Assert.IsFalse(asyncRes.IsCompleted); + + Assert.IsTrue(asyncRes.AsyncWaitHandle.WaitOne(1000)); + + Assert.IsTrue(asyncRes.IsCompleted); + } + + [Test] + public void TestFutureTypes() + { + TestType(false); + TestType((byte)11); + TestType('x'); // char + TestType(2.7d); // double + TestType(3.14f); // float + TestType(16); // int + TestType(17L); // long + TestType((short)18); + + TestType(18m); // decimal + + TestType(new Portable { A = 10, B = "foo" }); + } + + /// <summary> + /// Tests future type. + /// </summary> + private void TestType<T>(T value) + { + var key = typeof(T).Name; + + _cache.Put(key, value); + + _cache.GetFuture().Get(); + + _cache.Get(key); + + Assert.AreEqual(value, _cache.GetFuture<T>().Get()); + } + + /// <summary> + /// Portable test class. + /// </summary> + private class Portable : IPortableMarshalAware + { + public int A; + public string B; + + /** <inheritDoc /> */ + public void WritePortable(IPortableWriter writer) + { + writer.WriteInt("a", A); + writer.RawWriter().WriteString(B); + } + + /** <inheritDoc /> */ + public void ReadPortable(IPortableReader reader) + { + A = reader.ReadInt("a"); + B = reader.RawReader().ReadString(); + } + + /** <inheritDoc /> */ + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + return false; + + if (ReferenceEquals(this, obj)) + return true; + + if (obj.GetType() != GetType()) + return false; + + var other = (Portable)obj; + + return A == other.A && string.Equals(B, other.B); + } + + /** <inheritDoc /> */ + public override int GetHashCode() + { + unchecked + { + // ReSharper disable NonReadonlyMemberInGetHashCode + return (A * 397) ^ (B != null ? B.GetHashCode() : 0); + // ReSharper restore NonReadonlyMemberInGetHashCode + } + } + } + + /// <summary> + /// Compute action with a delay to ensure lengthy future execution. + /// </summary> + [Serializable] + private class SleepAction : IComputeAction + { + public void Invoke() + { + Thread.Sleep(500); + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteManagerTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteManagerTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteManagerTest.cs new file mode 100644 index 0000000..5a90c20 --- /dev/null +++ b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteManagerTest.cs @@ -0,0 +1,51 @@ +/* + * 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.IO; + using Apache.Ignite.Core.Impl; + using NUnit.Framework; + + /// <summary> + /// Tests IgniteManager class. + /// </summary> + public class IgniteManagerTest + { + /// <summary> + /// Tests home dir resolver. + /// </summary> + [Test] + public void TestIgniteHome() + { + var env = Environment.GetEnvironmentVariable(IgniteManager.EnvIgniteHome); + + Environment.SetEnvironmentVariable(IgniteManager.EnvIgniteHome, null); + + try + { + Assert.IsTrue(Directory.Exists(IgniteManager.GetIgniteHome(null))); + } + finally + { + // Restore + Environment.SetEnvironmentVariable(IgniteManager.EnvIgniteHome, env); + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteStartStopTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteStartStopTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteStartStopTest.cs new file mode 100644 index 0000000..d2b2efa --- /dev/null +++ b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgniteStartStopTest.cs @@ -0,0 +1,380 @@ +/* + * 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.Generic; + using System.Threading; + using Apache.Ignite.Core.Common; + using NUnit.Framework; + + /// <summary> + /// Ignite start/stop tests. + /// </summary> + [Category(TestUtils.CategoryIntensive)] + public class IgniteStartStopTest + { + /// <summary> + /// + /// </summary> + [SetUp] + public void SetUp() + { + TestUtils.KillProcesses(); + } + + /// <summary> + /// + /// </summary> + [TearDown] + public void TearDown() + { + Ignition.StopAll(true); + } + + /// <summary> + /// + /// </summary> + [Test] + public void TestStartDefault() + { + var cfg = new IgniteConfiguration {JvmClasspath = TestUtils.CreateTestClasspath()}; + + var grid = Ignition.Start(cfg); + + Assert.IsNotNull(grid); + + Assert.AreEqual(1, grid.Cluster.Nodes().Count); + } + + /// <summary> + /// + /// </summary> + [Test] + public void TestStartWithConfigPath() + { + var cfg = new IgniteConfiguration + { + SpringConfigUrl = "config/default-config.xml", + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + var grid = Ignition.Start(cfg); + + Assert.IsNotNull(grid); + + Assert.AreEqual(1, grid.Cluster.Nodes().Count); + } + + /// <summary> + /// + /// </summary> + [Test] + public void TestStartGetStop() + { + var cfgs = new List<string> { "config\\start-test-grid1.xml", "config\\start-test-grid2.xml", "config\\start-test-grid3.xml" }; + + var cfg = new IgniteConfiguration + { + SpringConfigUrl = cfgs[0], + JvmOptions = TestUtils.TestJavaOptions(), + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + var grid1 = Ignition.Start(cfg); + + Assert.AreEqual("grid1", grid1.Name); + + cfg.SpringConfigUrl = cfgs[1]; + + var grid2 = Ignition.Start(cfg); + + Assert.AreEqual("grid2", grid2.Name); + + cfg.SpringConfigUrl = cfgs[2]; + + var grid3 = Ignition.Start(cfg); + + Assert.IsNull(grid3.Name); + + Assert.AreSame(grid1, Ignition.GetIgnite("grid1")); + + Assert.AreSame(grid2, Ignition.GetIgnite("grid2")); + + Assert.AreSame(grid3, Ignition.GetIgnite(null)); + + try + { + Ignition.GetIgnite("invalid_name"); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + + Assert.IsTrue(Ignition.Stop("grid1", true)); + + try + { + Ignition.GetIgnite("grid1"); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + + grid2.Dispose(); + + try + { + Ignition.GetIgnite("grid2"); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + + grid3.Dispose(); + + try + { + Ignition.GetIgnite(null); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + + foreach (var cfgName in cfgs) + { + cfg.SpringConfigUrl = cfgName; + cfg.JvmOptions = TestUtils.TestJavaOptions(); + + Ignition.Start(cfg); + } + + foreach (var gridName in new List<string> { "grid1", "grid2", null }) + Assert.IsNotNull(Ignition.GetIgnite(gridName)); + + Ignition.StopAll(true); + + foreach (var gridName in new List<string> { "grid1", "grid2", null }) + { + try + { + Ignition.GetIgnite(gridName); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + } + } + + /* + [Test] + public void TestStartInvalidJvmOptions() + { + GridGain.Impl.IgniteManager.DestroyJvm(); + + IgniteConfiguration cfg = new IgniteConfiguration(); + + cfg.NativeXmlConfig = "config\\start-test-grid1.xml"; + cfg.NativeJvmOptions = new List<string> { "invalid_option"}; + + try + { + Ignition.Start(cfg); + + Assert.Fail("Start should fail."); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + + cfg.NativeJvmOptions = new List<string> { "-Xmx1g", "-Xms1g" }; + + Ignition.Start(cfg); + } + */ + + /// <summary> + /// + /// </summary> + [Test] + public void TestStartTheSameName() + { + var cfg = new IgniteConfiguration + { + SpringConfigUrl = "config\\start-test-grid1.xml", + JvmOptions = TestUtils.TestJavaOptions(), + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + var grid1 = Ignition.Start(cfg); + + Assert.AreEqual("grid1", grid1.Name); + + try + { + Ignition.Start(cfg); + + Assert.Fail("Start should fail."); + } + catch (IgniteException e) + { + Console.WriteLine("Expected exception: " + e); + } + } + + /// <summary> + /// + /// </summary> + [Test] + public void TestUsageAfterStop() + { + var cfg = new IgniteConfiguration + { + SpringConfigUrl = "config\\start-test-grid1.xml", + JvmOptions = TestUtils.TestJavaOptions(), + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + var grid = Ignition.Start(cfg); + + Assert.IsNotNull(grid.Cache<int, int>("cache1")); + + grid.Dispose(); + + try + { + grid.Cache<int, int>("cache1"); + + Assert.Fail(); + } + catch (InvalidOperationException e) + { + Console.WriteLine("Expected exception: " + e); + } + } + + /// <summary> + /// + /// </summary> + [Test] + public void TestStartStopLeak() + { + var cfg = new IgniteConfiguration + { + SpringConfigUrl = "config\\start-test-grid1.xml", + JvmOptions = new List<string> {"-Xcheck:jni", "-Xms256m", "-Xmx256m", "-XX:+HeapDumpOnOutOfMemoryError"}, + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + for (var i = 0; i < 20; i++) + { + Console.WriteLine("Iteration: " + i); + + var grid = Ignition.Start(cfg); + + UseIgnite(grid); + + if (i % 2 == 0) // Try to stop ignite from another thread. + { + var t = new Thread(() => { + grid.Dispose(); + }); + + t.Start(); + + t.Join(); + } + else + grid.Dispose(); + + GC.Collect(); // At the time of writing java references are cleaned from finalizer, so GC is needed. + } + } + + /// <summary> + /// Tests the client mode flag. + /// </summary> + [Test] + public void TestClientMode() + { + var servCfg = new IgniteConfiguration + { + SpringConfigUrl = "config\\start-test-grid1.xml", + JvmOptions = TestUtils.TestJavaOptions(), + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + var clientCfg = new IgniteConfiguration + { + SpringConfigUrl = "config\\start-test-grid2.xml", + JvmOptions = TestUtils.TestJavaOptions(), + JvmClasspath = TestUtils.CreateTestClasspath() + }; + + try + { + using (Ignition.Start(servCfg)) // start server-mode ignite first + { + Ignition.ClientMode = true; + + using (var grid = Ignition.Start(clientCfg)) + { + UseIgnite(grid); + } + } + } + finally + { + Ignition.ClientMode = false; + } + } + + /// <summary> + /// Uses the ignite. + /// </summary> + /// <param name="ignite">The ignite.</param> + private static void UseIgnite(IIgnite ignite) + { + // Create objects holding references to java objects. + var comp = ignite.Compute(); + + // ReSharper disable once RedundantAssignment + comp = comp.WithKeepPortable(); + + var prj = ignite.Cluster.ForOldest(); + + Assert.IsTrue(prj.Nodes().Count > 0); + + Assert.IsNotNull(prj.Compute()); + + var cache = ignite.Cache<int, int>("cache1"); + + Assert.IsNotNull(cache); + + cache.GetAndPut(1, 1); + + Assert.AreEqual(1, cache.Get(1)); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgnitionTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgnitionTest.cs b/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgnitionTest.cs deleted file mode 100644 index a2698d1..0000000 --- a/modules/platform/src/test/dotnet/Apache.Ignite.Core.Tests/IgnitionTest.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 NUnit.Framework; - - public class IgnitionTest - { - [Test] - public void Test() - { - Assert.IsNotNull(new Ignition()); - } - } -}
