Return-Path: X-Original-To: apmail-ignite-commits-archive@minotaur.apache.org Delivered-To: apmail-ignite-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id CF17B17200 for ; Tue, 22 Sep 2015 07:19:11 +0000 (UTC) Received: (qmail 16752 invoked by uid 500); 22 Sep 2015 07:19:05 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 16672 invoked by uid 500); 22 Sep 2015 07:19:05 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 15125 invoked by uid 99); 22 Sep 2015 07:19:04 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 22 Sep 2015 07:19:04 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 61F2AE0613; Tue, 22 Sep 2015 07:19:04 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: vozerov@apache.org To: commits@ignite.apache.org Date: Tue, 22 Sep 2015 07:19:35 -0000 Message-Id: <339f528d275449a7b4c171cd2b07125b@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [33/37] ignite git commit: IGNITE-1513: WIP on .Net. http://git-wip-us.apache.org/repos/asf/ignite/blob/65bb69da/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/AbstractTaskTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/AbstractTaskTest.cs b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/AbstractTaskTest.cs new file mode 100644 index 0000000..12c9992 --- /dev/null +++ b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/AbstractTaskTest.cs @@ -0,0 +1,217 @@ +/* + * 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.Compute +{ + using System; + using System.Collections.Generic; + using System.Threading; + using Apache.Ignite.Core.Portable; + using Apache.Ignite.Core.Tests.Process; + using NUnit.Framework; + + /// + /// Base class for all task-related tests. + /// + public abstract class AbstractTaskTest + { + /** */ + protected const string Grid1Name = "grid1"; + + /** */ + protected const string Grid2Name = "grid2"; + + /** */ + protected const string Grid3Name = "grid3"; + + /** */ + protected const string Cache1Name = "cache1"; + + /** Whether this is a test with forked JVMs. */ + private readonly bool _fork; + + /** First node. */ + [NonSerialized] + protected IIgnite Grid1; + + /** Second node. */ + [NonSerialized] + private IIgnite _grid2; + + /** Third node. */ + [NonSerialized] + private IIgnite _grid3; + + /** Second process. */ + [NonSerialized] + private IgniteProcess _proc2; + + /** Third process. */ + [NonSerialized] + private IgniteProcess _proc3; + + /// + /// Constructor. + /// + /// Fork flag. + protected AbstractTaskTest(bool fork) + { + _fork = fork; + } + + /// + /// Initialization routine. + /// + [TestFixtureSetUp] + public void InitClient() + { + TestUtils.KillProcesses(); + + if (_fork) + { + Grid1 = Ignition.Start(Configuration("config\\compute\\compute-standalone.xml")); + + _proc2 = Fork("config\\compute\\compute-standalone.xml"); + + while (true) + { + if (!_proc2.Alive) + throw new Exception("Process 2 died unexpectedly: " + _proc2.Join()); + + if (Grid1.GetCluster().GetNodes().Count < 2) + Thread.Sleep(100); + else + break; + } + + _proc3 = Fork("config\\compute\\compute-standalone.xml"); + + while (true) + { + if (!_proc3.Alive) + throw new Exception("Process 3 died unexpectedly: " + _proc3.Join()); + + if (Grid1.GetCluster().GetNodes().Count < 3) + Thread.Sleep(100); + else + break; + } + } + else + { + 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")); + } + } + + [SetUp] + public void BeforeTest() + { + Console.WriteLine("Test started: " + TestContext.CurrentContext.Test.Name); + } + + [TestFixtureTearDown] + public void StopClient() + { + if (Grid1 != null) + Ignition.Stop(Grid1.Name, true); + + if (_fork) + { + if (_proc2 != null) { + _proc2.Kill(); + + _proc2.Join(); + } + + if (_proc3 != null) + { + _proc3.Kill(); + + _proc3.Join(); + } + } + else + { + if (_grid2 != null) + Ignition.Stop(_grid2.Name, true); + + if (_grid3 != null) + Ignition.Stop(_grid3.Name, true); + } + } + + /// + /// Configuration for node. + /// + /// Path to Java XML configuration. + /// Node configuration. + protected IgniteConfiguration Configuration(string path) + { + IgniteConfiguration cfg = new IgniteConfiguration(); + + if (!_fork) + { + PortableConfiguration portCfg = new PortableConfiguration(); + + ICollection portTypeCfgs = new List(); + + PortableTypeConfigurations(portTypeCfgs); + + portCfg.TypeConfigurations = portTypeCfgs; + + cfg.PortableConfiguration = portCfg; + } + + cfg.JvmClasspath = TestUtils.CreateTestClasspath(); + + cfg.JvmOptions = TestUtils.TestJavaOptions(); + + cfg.SpringConfigUrl = path; + + return cfg; + } + + /// + /// Create forked process with the following Spring config. + /// + /// Path to Java XML configuration. + /// Forked process. + private static IgniteProcess Fork(string path) + { + return new IgniteProcess( + "-springConfigUrl=" + path, + "-J-ea", + "-J-Xcheck:jni", + "-J-Xms512m", + "-J-Xmx512m", + "-J-DIGNITE_QUIET=false" + //"-J-Xnoagent", "-J-Djava.compiler=NONE", "-J-Xdebug", "-J-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006" + ); + } + + /// + /// Define portable types. + /// + /// Portable type configurations. + protected virtual void PortableTypeConfigurations(ICollection portTypeCfgs) + { + // No-op. + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/65bb69da/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ClosureTaskTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ClosureTaskTest.cs b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ClosureTaskTest.cs new file mode 100644 index 0000000..8664413 --- /dev/null +++ b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ClosureTaskTest.cs @@ -0,0 +1,390 @@ +/* + * 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.Compute +{ + using System; + using System.Collections.Generic; + using Apache.Ignite.Core.Compute; + using NUnit.Framework; + + /// + /// Tests for distributed closure executions. + /// + public abstract class ClosureTaskTest : AbstractTaskTest + { + /** Amount of multiple clousres. */ + private const int MultiCloCnt = 5; + + /** */ + protected const string ErrMsg = "An error has occurred."; + + /// + /// Constructor. + /// + /// Fork mode. + protected ClosureTaskTest(bool fork) : base(fork) { } + + /// + /// Test for single closure returning result. + /// + [Test] + public void TestExecuteSingle() + { + var res = Grid1.GetCompute().Call(OutFunc(false)); + + CheckResult(res); + } + + /// + /// Test for single closure returning exception. + /// + [Test] + public void TestExecuteSingleException() + { + try + { + Grid1.GetCompute().Call(OutFunc(true)); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test for multiple closures execution. + /// + [Test] + public void TestExecuteMultiple() + { + var clos = new List>(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + clos.Add(OutFunc(false)); + + ICollection ress = Grid1.GetCompute().Call(clos); + + foreach (object res in ress) + CheckResult(res); + } + + /// + /// Test for multiple closures execution. + /// + [Test] + public void TestExecuteMultipleReduced() + { + var clos = new List>(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + clos.Add(OutFunc(false)); + + ICollection ress = Grid1.GetCompute().Call(clos, new Reducer(false)); + + foreach (object res in ress) + CheckResult(res); + } + + /// + /// Test for multiple closures execution with exceptions thrown from some of them. + /// + [Test] + public void TestExecuteMultipleException() + { + var clos = new List>(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + clos.Add(OutFunc(i % 2 == 0)); // Some closures will be faulty. + + try + { + Grid1.GetCompute().Call(clos); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test broadcast out-closure execution. + /// + [Test] + public void TestBroadcastOut() + { + ICollection ress = Grid1.GetCompute().Broadcast(OutFunc(false)); + + foreach (object res in ress) + CheckResult(res); + } + + /// + /// Test broadcast out-closure execution with exception. + /// + [Test] + public void TestBroadcastOutException() + { + try + { + Grid1.GetCompute().Broadcast(OutFunc(true)); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test broadcast in-out-closure execution. + /// + [Test] + public void TestBroadcastInOut() + { + ICollection ress = Grid1.GetCompute().Broadcast(Func(false), 1); + + foreach (object res in ress) + CheckResult(res); + } + + /// + /// Test broadcast in-out-closure execution with exception. + /// + [Test] + public void TestBroadcastInOutException() + { + try + { + Grid1.GetCompute().Broadcast(Func(true), 1); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test apply in-out-closure execution. + /// + [Test] + public void TestApply() + { + object res = Grid1.GetCompute().Apply(Func(false), 1); + + CheckResult(res); + } + + /// + /// Test apply in-out-closure execution with exception. + /// + [Test] + public void TestApplyException() + { + try + { + Grid1.GetCompute().Apply(Func(true), 1); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test apply multiple in-out-closures execution. + /// + [Test] + public void TestApplyMultiple() + { + var args = new List(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + args.Add(1); + + Console.WriteLine("START TASK"); + + var ress = Grid1.GetCompute().Apply(Func(false), args); + + Console.WriteLine("END TASK."); + + foreach (object res in ress) + CheckResult(res); + } + + /// + /// Test apply multiple in-out-closures execution with exception. + /// + [Test] + public void TestApplyMultipleException() + { + ICollection args = new List(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + args.Add(1); + + try + { + Grid1.GetCompute().Apply(Func(true), args); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test apply multiple in-out-closures execution with reducer. + /// + [Test] + public void TestApplyMultipleReducer() + { + var args = new List(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + args.Add(1); + + ICollection ress = + Grid1.GetCompute().Apply(Func(false), args, new Reducer(false)); + + foreach (object res in ress) + CheckResult(res); + } + + /// + /// Test apply multiple in-out-closures execution with reducer and exception thrown from closure. + /// + [Test] + public void TestAppylMultipleReducerJobException() + { + List args = new List(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + args.Add(1); + + try + { + Grid1.GetCompute().Apply(Func(true), args, new Reducer(false)); + + Assert.Fail(); + } + catch (Exception e) + { + CheckError(e); + } + } + + /// + /// Test apply multiple in-out-closures execution with reducer and exception thrown from reducer. + /// + [Test] + public void TestAppylMultipleReducerReduceException() + { + var args = new List(MultiCloCnt); + + for (int i = 0; i < MultiCloCnt; i++) + args.Add(1); + + try + { + Grid1.GetCompute().Apply(Func(false), args, new Reducer(true)); + + Assert.Fail(); + } + catch (Exception e) + { + Assert.AreEqual(typeof(Exception), e.GetType()); + + Assert.AreEqual(ErrMsg, e.Message); + } + } + + /// + /// Create out-only closure. + /// + /// Error flag. + /// Closure. + protected abstract IComputeFunc OutFunc(bool err); + + /// + /// Create in-out closure. + /// + /// Error flag. + /// Closure. + protected abstract IComputeFunc Func(bool err); + + /// + /// Check result. + /// + /// Result. + protected abstract void CheckResult(object res); + + /// + /// Check error. + /// + /// Error. + protected abstract void CheckError(Exception err); + + /// + /// Test reducer. + /// + public class Reducer : IComputeReducer> + { + /** Whether to throw an error on reduce. */ + private readonly bool _err; + + /** Results. */ + private readonly ICollection _ress = new List(); + + /// + /// Constructor. + /// + /// Error. + public Reducer(bool err) + { + _err = err; + } + + /** */ + public bool Collect(object res) + { + _ress.Add(res); + + return true; + } + + /** */ + public ICollection Reduce() + { + if (_err) + throw new Exception(ErrMsg); + return _ress; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/65bb69da/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs new file mode 100644 index 0000000..039813b --- /dev/null +++ b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs @@ -0,0 +1,1281 @@ +/* + * 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 SpecifyACultureInStringConversionExplicitly +namespace Apache.Ignite.Core.Tests.Compute +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Compute; + using Apache.Ignite.Core.Impl; + using Apache.Ignite.Core.Portable; + using Apache.Ignite.Core.Resource; + using NUnit.Framework; + + /// + /// Tests for compute. + /// + public class ComputeApiTest + { + /** Echo task name. */ + private const string EchoTask = "org.apache.ignite.platform.PlatformComputeEchoTask"; + + /** Portable argument task name. */ + private const string PortableArgTask = "org.apache.ignite.platform.PlatformComputePortableArgTask"; + + /** Broadcast task name. */ + private const string BroadcastTask = "org.apache.ignite.platform.PlatformComputeBroadcastTask"; + + /** Broadcast task name. */ + private const string DecimalTask = "org.apache.ignite.platform.PlatformComputeDecimalTask"; + + /** Java portable class name. */ + private const string JavaPortableCls = "GridInteropComputeJavaPortable"; + + /** Echo type: null. */ + private const int EchoTypeNull = 0; + + /** Echo type: byte. */ + private const int EchoTypeByte = 1; + + /** Echo type: bool. */ + private const int EchoTypeBool = 2; + + /** Echo type: short. */ + private const int EchoTypeShort = 3; + + /** Echo type: char. */ + private const int EchoTypeChar = 4; + + /** Echo type: int. */ + private const int EchoTypeInt = 5; + + /** Echo type: long. */ + private const int EchoTypeLong = 6; + + /** Echo type: float. */ + private const int EchoTypeFloat = 7; + + /** Echo type: double. */ + private const int EchoTypeDouble = 8; + + /** Echo type: array. */ + private const int EchoTypeArray = 9; + + /** Echo type: collection. */ + private const int EchoTypeCollection = 10; + + /** Echo type: map. */ + private const int EchoTypeMap = 11; + + /** Echo type: portable. */ + private const int EchoTypePortable = 12; + + /** Echo type: portable (Java only). */ + private const int EchoTypePortableJava = 13; + + /** Type: object array. */ + private const int EchoTypeObjArray = 14; + + /** Type: portable object array. */ + private const int EchoTypePortableArray = 15; + + /** Type: enum. */ + private const int EchoTypeEnum = 16; + + /** Type: enum array. */ + private const int EchoTypeEnumArray = 17; + + /** First node. */ + private IIgnite _grid1; + + /** Second node. */ + private IIgnite _grid2; + + /** Third node. */ + private IIgnite _grid3; + + /// + /// Initialization routine. + /// + [TestFixtureSetUp] + public void InitClient() + { + //TestUtils.JVM_DEBUG = true; + TestUtils.KillProcesses(); + + _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")); + } + + [TestFixtureTearDown] + public void StopClient() + { + if (_grid1 != null) + Ignition.Stop(_grid1.Name, true); + + if (_grid2 != null) + Ignition.Stop(_grid2.Name, true); + + if (_grid3 != null) + Ignition.Stop(_grid3.Name, true); + } + + [TearDown] + public void AfterTest() + { + TestUtils.AssertHandleRegistryIsEmpty(1000, _grid1, _grid2, _grid3); + } + + /// + /// Test that it is possible to get projection from grid. + /// + [Test] + public void TestProjection() + { + IClusterGroup prj = _grid1.GetCluster(); + + Assert.NotNull(prj); + + Assert.IsTrue(prj == prj.Ignite); + } + + /// + /// Test getting cache with default (null) name. + /// + [Test] + public void TestCacheDefaultName() + { + var cache = _grid1.GetCache(null); + + Assert.IsNotNull(cache); + + cache.GetAndPut(1, 1); + + Assert.AreEqual(1, cache.Get(1)); + } + + /// + /// Test non-existent cache. + /// + [Test] + public void TestNonExistentCache() + { + Assert.Catch(typeof(ArgumentException), () => + { + _grid1.GetCache("bad_name"); + }); + } + + /// + /// Test node content. + /// + [Test] + public void TestNodeContent() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + foreach (IClusterNode node in nodes) + { + Assert.NotNull(node.Addresses); + Assert.IsTrue(node.Addresses.Count > 0); + Assert.Throws(() => node.Addresses.Add("addr")); + + Assert.NotNull(node.GetAttributes()); + Assert.IsTrue(node.GetAttributes().Count > 0); + Assert.Throws(() => node.GetAttributes().Add("key", "val")); + + Assert.NotNull(node.HostNames); + Assert.Throws(() => node.HostNames.Add("h")); + + Assert.IsTrue(node.Id != Guid.Empty); + + Assert.IsTrue(node.Order > 0); + + Assert.NotNull(node.GetMetrics()); + } + } + + /// + /// Test cluster metrics. + /// + [Test] + public void TestClusterMetrics() + { + var cluster = _grid1.GetCluster(); + + IClusterMetrics metrics = cluster.GetMetrics(); + + Assert.IsNotNull(metrics); + + Assert.AreEqual(cluster.GetNodes().Count, metrics.TotalNodes); + + Thread.Sleep(2000); + + IClusterMetrics newMetrics = cluster.GetMetrics(); + + Assert.IsFalse(metrics == newMetrics); + Assert.IsTrue(metrics.LastUpdateTime < newMetrics.LastUpdateTime); + } + + /// + /// Test cluster metrics. + /// + [Test] + public void TestNodeMetrics() + { + var node = _grid1.GetCluster().GetNode(); + + IClusterMetrics metrics = node.GetMetrics(); + + Assert.IsNotNull(metrics); + + Assert.IsTrue(metrics == node.GetMetrics()); + + Thread.Sleep(2000); + + IClusterMetrics newMetrics = node.GetMetrics(); + + Assert.IsFalse(metrics == newMetrics); + Assert.IsTrue(metrics.LastUpdateTime < newMetrics.LastUpdateTime); + } + + /// + /// Test cluster metrics. + /// + [Test] + public void TestResetMetrics() + { + var cluster = _grid1.GetCluster(); + + Thread.Sleep(2000); + + var metrics1 = cluster.GetMetrics(); + + cluster.ResetMetrics(); + + var metrics2 = cluster.GetMetrics(); + + Assert.IsNotNull(metrics1); + Assert.IsNotNull(metrics2); + } + + /// + /// Test node ping. + /// + [Test] + public void TestPingNode() + { + var cluster = _grid1.GetCluster(); + + Assert.IsTrue(cluster.GetNodes().Select(node => node.Id).All(cluster.PingNode)); + + Assert.IsFalse(cluster.PingNode(Guid.NewGuid())); + } + + /// + /// Tests the topology version. + /// + [Test] + public void TestTopologyVersion() + { + var cluster = _grid1.GetCluster(); + + var topVer = cluster.TopologyVersion; + + Ignition.Stop(_grid3.Name, true); + + Assert.AreEqual(topVer + 1, _grid1.GetCluster().TopologyVersion); + + _grid3 = Ignition.Start(Configuration("config\\compute\\compute-grid3.xml")); + + Assert.AreEqual(topVer + 2, _grid1.GetCluster().TopologyVersion); + } + + /// + /// Tests the topology by version. + /// + [Test] + public void TestTopology() + { + var cluster = _grid1.GetCluster(); + + Assert.AreEqual(1, cluster.GetTopology(1).Count); + + Assert.AreEqual(null, cluster.GetTopology(int.MaxValue)); + + // Check that Nodes and Topology return the same for current version + var topVer = cluster.TopologyVersion; + + var top = cluster.GetTopology(topVer); + + var nodes = cluster.GetNodes(); + + Assert.AreEqual(top.Count, nodes.Count); + + Assert.IsTrue(top.All(nodes.Contains)); + + // Stop/start node to advance version and check that history is still correct + Assert.IsTrue(Ignition.Stop(_grid2.Name, true)); + + try + { + top = cluster.GetTopology(topVer); + + Assert.AreEqual(top.Count, nodes.Count); + + Assert.IsTrue(top.All(nodes.Contains)); + } + finally + { + _grid2 = Ignition.Start(Configuration("config\\compute\\compute-grid2.xml")); + } + } + + /// + /// Test nodes in full topology. + /// + [Test] + public void TestNodes() + { + Assert.IsNotNull(_grid1.GetCluster().GetNode()); + + ICollection nodes = _grid1.GetCluster().GetNodes(); + + Assert.IsTrue(nodes.Count == 3); + + // Check subsequent call on the same topology. + nodes = _grid1.GetCluster().GetNodes(); + + Assert.IsTrue(nodes.Count == 3); + + Assert.IsTrue(Ignition.Stop(_grid2.Name, true)); + + // Check subsequent calls on updating topologies. + nodes = _grid1.GetCluster().GetNodes(); + + Assert.IsTrue(nodes.Count == 2); + + nodes = _grid1.GetCluster().GetNodes(); + + Assert.IsTrue(nodes.Count == 2); + + _grid2 = Ignition.Start(Configuration("config\\compute\\compute-grid2.xml")); + + nodes = _grid1.GetCluster().GetNodes(); + + Assert.IsTrue(nodes.Count == 3); + } + + /// + /// Test "ForNodes" and "ForNodeIds". + /// + [Test] + public void TestForNodes() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + IClusterNode first = nodes.ElementAt(0); + IClusterNode second = nodes.ElementAt(1); + + IClusterGroup singleNodePrj = _grid1.GetCluster().ForNodeIds(first.Id); + Assert.AreEqual(1, singleNodePrj.GetNodes().Count); + Assert.AreEqual(first.Id, singleNodePrj.GetNodes().First().Id); + + singleNodePrj = _grid1.GetCluster().ForNodeIds(new List { first.Id }); + Assert.AreEqual(1, singleNodePrj.GetNodes().Count); + Assert.AreEqual(first.Id, singleNodePrj.GetNodes().First().Id); + + singleNodePrj = _grid1.GetCluster().ForNodes(first); + Assert.AreEqual(1, singleNodePrj.GetNodes().Count); + Assert.AreEqual(first.Id, singleNodePrj.GetNodes().First().Id); + + singleNodePrj = _grid1.GetCluster().ForNodes(new List { first }); + Assert.AreEqual(1, singleNodePrj.GetNodes().Count); + Assert.AreEqual(first.Id, singleNodePrj.GetNodes().First().Id); + + IClusterGroup multiNodePrj = _grid1.GetCluster().ForNodeIds(first.Id, second.Id); + Assert.AreEqual(2, multiNodePrj.GetNodes().Count); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(first)); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(second)); + + multiNodePrj = _grid1.GetCluster().ForNodeIds(new[] {first, second}.Select(x => x.Id)); + Assert.AreEqual(2, multiNodePrj.GetNodes().Count); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(first)); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(second)); + + multiNodePrj = _grid1.GetCluster().ForNodes(first, second); + Assert.AreEqual(2, multiNodePrj.GetNodes().Count); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(first)); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(second)); + + multiNodePrj = _grid1.GetCluster().ForNodes(new List { first, second }); + Assert.AreEqual(2, multiNodePrj.GetNodes().Count); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(first)); + Assert.IsTrue(multiNodePrj.GetNodes().Contains(second)); + } + + /// + /// Test "ForNodes" and "ForNodeIds". Make sure lazy enumerables are enumerated only once. + /// + [Test] + public void TestForNodesLaziness() + { + var nodes = _grid1.GetCluster().GetNodes().Take(2).ToArray(); + + var callCount = 0; + + Func nodeSelector = node => + { + callCount++; + return node; + }; + + Func idSelector = node => + { + callCount++; + return node.Id; + }; + + var projection = _grid1.GetCluster().ForNodes(nodes.Select(nodeSelector)); + Assert.AreEqual(2, projection.GetNodes().Count); + Assert.AreEqual(2, callCount); + + projection = _grid1.GetCluster().ForNodeIds(nodes.Select(idSelector)); + Assert.AreEqual(2, projection.GetNodes().Count); + Assert.AreEqual(4, callCount); + } + + /// + /// Test for local node projection. + /// + [Test] + public void TestForLocal() + { + IClusterGroup prj = _grid1.GetCluster().ForLocal(); + + Assert.AreEqual(1, prj.GetNodes().Count); + Assert.AreEqual(_grid1.GetCluster().GetLocalNode(), prj.GetNodes().First()); + } + + /// + /// Test for remote nodes projection. + /// + [Test] + public void TestForRemotes() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + IClusterGroup prj = _grid1.GetCluster().ForRemotes(); + + Assert.AreEqual(2, prj.GetNodes().Count); + Assert.IsTrue(nodes.Contains(prj.GetNodes().ElementAt(0))); + Assert.IsTrue(nodes.Contains(prj.GetNodes().ElementAt(1))); + } + + /// + /// Test for host nodes projection. + /// + [Test] + public void TestForHost() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + IClusterGroup prj = _grid1.GetCluster().ForHost(nodes.First()); + + Assert.AreEqual(3, prj.GetNodes().Count); + Assert.IsTrue(nodes.Contains(prj.GetNodes().ElementAt(0))); + Assert.IsTrue(nodes.Contains(prj.GetNodes().ElementAt(1))); + Assert.IsTrue(nodes.Contains(prj.GetNodes().ElementAt(2))); + } + + /// + /// Test for oldest, youngest and random projections. + /// + [Test] + public void TestForOldestYoungestRandom() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + IClusterGroup prj = _grid1.GetCluster().ForYoungest(); + Assert.AreEqual(1, prj.GetNodes().Count); + Assert.IsTrue(nodes.Contains(prj.GetNode())); + + prj = _grid1.GetCluster().ForOldest(); + Assert.AreEqual(1, prj.GetNodes().Count); + Assert.IsTrue(nodes.Contains(prj.GetNode())); + + prj = _grid1.GetCluster().ForRandom(); + Assert.AreEqual(1, prj.GetNodes().Count); + Assert.IsTrue(nodes.Contains(prj.GetNode())); + } + + /// + /// Test for attribute projection. + /// + [Test] + public void TestForAttribute() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + IClusterGroup prj = _grid1.GetCluster().ForAttribute("my_attr", "value1"); + Assert.AreEqual(1, prj.GetNodes().Count); + Assert.IsTrue(nodes.Contains(prj.GetNode())); + Assert.AreEqual("value1", prj.GetNodes().First().GetAttribute("my_attr")); + } + + /// + /// Test for cache/data/client projections. + /// + [Test] + public void TestForCacheNodes() + { + ICollection nodes = _grid1.GetCluster().GetNodes(); + + // Cache nodes. + IClusterGroup prjCache = _grid1.GetCluster().ForCacheNodes("cache1"); + + Assert.AreEqual(2, prjCache.GetNodes().Count); + + Assert.IsTrue(nodes.Contains(prjCache.GetNodes().ElementAt(0))); + Assert.IsTrue(nodes.Contains(prjCache.GetNodes().ElementAt(1))); + + // Data nodes. + IClusterGroup prjData = _grid1.GetCluster().ForDataNodes("cache1"); + + Assert.AreEqual(2, prjData.GetNodes().Count); + + Assert.IsTrue(prjCache.GetNodes().Contains(prjData.GetNodes().ElementAt(0))); + Assert.IsTrue(prjCache.GetNodes().Contains(prjData.GetNodes().ElementAt(1))); + + // Client nodes. + IClusterGroup prjClient = _grid1.GetCluster().ForClientNodes("cache1"); + + Assert.AreEqual(0, prjClient.GetNodes().Count); + } + + /// + /// Test for cache predicate. + /// + [Test] + public void TestForPredicate() + { + IClusterGroup prj1 = _grid1.GetCluster().ForPredicate(new NotAttributePredicate("value1").Apply); + Assert.AreEqual(2, prj1.GetNodes().Count); + + IClusterGroup prj2 = prj1.ForPredicate(new NotAttributePredicate("value2").Apply); + Assert.AreEqual(1, prj2.GetNodes().Count); + + string val; + + prj2.GetNodes().First().TryGetAttribute("my_attr", out val); + + Assert.IsTrue(val == null || (!val.Equals("value1") && !val.Equals("value2"))); + } + + /// + /// Attribute predicate. + /// + private class NotAttributePredicate + { + /** Required attribute value. */ + private readonly string _attrVal; + + /// + /// Constructor. + /// + /// Required attribute value. + public NotAttributePredicate(string attrVal) + { + _attrVal = attrVal; + } + + /** */ + public bool Apply(IClusterNode node) + { + string val; + + node.TryGetAttribute("my_attr", out val); + + return val == null || !val.Equals(_attrVal); + } + } + + /// + /// Test echo with decimals. + /// + [Test] + public void TestEchoDecimal() + { + decimal val; + + Assert.AreEqual(val = decimal.Zero, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = new decimal(0, 0, 1, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, 1, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, 1, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, 1, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, 1, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, 1, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MinValue, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MinValue, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MinValue, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MinValue, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MinValue, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MinValue, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MaxValue, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MaxValue, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MaxValue, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MaxValue, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MaxValue, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 0, int.MaxValue, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = new decimal(0, 1, 0, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 1, 0, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 1, 0, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 1, 0, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 1, 0, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, 1, 0, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MinValue, 0, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MinValue, 0, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MinValue, 0, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MinValue, 0, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MinValue, 0, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MinValue, 0, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MaxValue, 0, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MaxValue, 0, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MaxValue, 0, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MaxValue, 0, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MaxValue, 0, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(0, int.MaxValue, 0, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = new decimal(1, 0, 0, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 0, 0, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 0, 0, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 0, 0, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 0, 0, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 0, 0, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MinValue, 0, 0, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MinValue, 0, 0, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MinValue, 0, 0, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MinValue, 0, 0, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MinValue, 0, 0, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MinValue, 0, 0, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MaxValue, 0, 0, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MaxValue, 0, 0, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MaxValue, 0, 0, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MaxValue, 0, 0, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MaxValue, 0, 0, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(int.MaxValue, 0, 0, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = new decimal(1, 1, 1, false, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 1, 1, true, 0), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 1, 1, false, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 1, 1, true, 0) - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 1, 1, false, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = new decimal(1, 1, 1, true, 0) + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.Parse("65536"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-65536"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("65536") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-65536") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("65536") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-65536") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.Parse("4294967296"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-4294967296"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("4294967296") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-4294967296") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("4294967296") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-4294967296") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.Parse("281474976710656"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-281474976710656"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("281474976710656") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-281474976710656") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("281474976710656") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-281474976710656") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.Parse("18446744073709551616"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-18446744073709551616"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("18446744073709551616") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-18446744073709551616") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("18446744073709551616") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-18446744073709551616") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.Parse("1208925819614629174706176"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-1208925819614629174706176"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("1208925819614629174706176") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-1208925819614629174706176") - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("1208925819614629174706176") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-1208925819614629174706176") + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.MaxValue, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.MinValue, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.MaxValue - 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.MinValue + 1, _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + Assert.AreEqual(val = decimal.Parse("11,12"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + Assert.AreEqual(val = decimal.Parse("-11,12"), _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { val, val.ToString() })); + + // Test echo with overflow. + try + { + _grid1.GetCompute().ExecuteJavaTask(DecimalTask, new object[] { null, decimal.MaxValue.ToString() + 1 }); + + Assert.Fail(); + } + catch (IgniteException) + { + // No-op. + } + } + + /// + /// Test echo task returning null. + /// + [Test] + public void TestEchoTaskNull() + { + Assert.IsNull(_grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeNull)); + } + + /// + /// Test echo task returning various primitives. + /// + [Test] + public void TestEchoTaskPrimitives() + { + Assert.AreEqual(1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeByte)); + Assert.AreEqual(true, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeBool)); + Assert.AreEqual(1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeShort)); + Assert.AreEqual((char)1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeChar)); + Assert.AreEqual(1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeInt)); + Assert.AreEqual(1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeLong)); + Assert.AreEqual((float)1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeFloat)); + Assert.AreEqual((double)1, _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeDouble)); + } + + /// + /// Test echo task returning compound types. + /// + [Test] + public void TestEchoTaskCompound() + { + int[] res1 = _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeArray); + + Assert.AreEqual(1, res1.Length); + Assert.AreEqual(1, res1[0]); + + IList res2 = _grid1.GetCompute().ExecuteJavaTask>(EchoTask, EchoTypeCollection); + + Assert.AreEqual(1, res2.Count); + Assert.AreEqual(1, res2[0]); + + IDictionary res3 = _grid1.GetCompute().ExecuteJavaTask>(EchoTask, EchoTypeMap); + + Assert.AreEqual(1, res3.Count); + Assert.AreEqual(1, res3[1]); + } + + /// + /// Test echo task returning portable object. + /// + [Test] + public void TestEchoTaskPortable() + { + PlatformComputePortable res = _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypePortable); + + Assert.AreEqual(1, res.Field); + } + + /// + /// Test echo task returning portable object with no corresponding class definition. + /// + [Test] + public void TestEchoTaskPortableNoClass() + { + ICompute compute = _grid1.GetCompute(); + + compute.WithKeepPortable(); + + IPortableObject res = compute.ExecuteJavaTask(EchoTask, EchoTypePortableJava); + + Assert.AreEqual(1, res.GetField("field")); + + // This call must fail because "keepPortable" flag is reset. + Assert.Catch(typeof(PortableException), () => + { + compute.ExecuteJavaTask(EchoTask, EchoTypePortableJava); + }); + } + + /// + /// Tests the echo task returning object array. + /// + [Test] + public void TestEchoTaskObjectArray() + { + var res = _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeObjArray); + + Assert.AreEqual(new[] {"foo", "bar", "baz"}, res); + } + + /// + /// Tests the echo task returning portable array. + /// + [Test] + public void TestEchoTaskPortableArray() + { + var res = _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypePortableArray); + + Assert.AreEqual(3, res.Length); + + for (var i = 0; i < res.Length; i++) + Assert.AreEqual(i + 1, res[i].Field); + } + + /// + /// Tests the echo task returning enum. + /// + [Test] + public void TestEchoTaskEnum() + { + var res = _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeEnum); + + Assert.AreEqual(InteropComputeEnum.Bar, res); + } + + /// + /// Tests the echo task returning enum. + /// + [Test] + public void TestEchoTaskEnumArray() + { + var res = _grid1.GetCompute().ExecuteJavaTask(EchoTask, EchoTypeEnumArray); + + Assert.AreEqual(new[] + { + InteropComputeEnum.Bar, + InteropComputeEnum.Baz, + InteropComputeEnum.Foo + }, res); + } + + /// + /// Test for portable argument in Java. + /// + [Test] + public void TestPortableArgTask() + { + ICompute compute = _grid1.GetCompute(); + + compute.WithKeepPortable(); + + PlatformComputeNetPortable arg = new PlatformComputeNetPortable(); + + arg.Field = 100; + + int res = compute.ExecuteJavaTask(PortableArgTask, arg); + + Assert.AreEqual(arg.Field, res); + } + + /// + /// Test running broadcast task. + /// + [Test] + public void TestBroadcastTask() + { + ICollection res = _grid1.GetCompute().ExecuteJavaTask>(BroadcastTask, null); + + Assert.AreEqual(3, res.Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(0)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(1)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(2)).GetNodes().Count); + + var prj = _grid1.GetCluster().ForPredicate(node => res.Take(2).Contains(node.Id)); + + Assert.AreEqual(2, prj.GetNodes().Count); + + ICollection filteredRes = prj.GetCompute().ExecuteJavaTask>(BroadcastTask, null); + + Assert.AreEqual(2, filteredRes.Count); + Assert.IsTrue(filteredRes.Contains(res.ElementAt(0))); + Assert.IsTrue(filteredRes.Contains(res.ElementAt(1))); + } + + /// + /// Test running broadcast task in async mode. + /// + [Test] + public void TestBroadcastTaskAsync() + { + var gridCompute = _grid1.GetCompute().WithAsync(); + Assert.IsNull(gridCompute.ExecuteJavaTask>(BroadcastTask, null)); + ICollection res = gridCompute.GetFuture>().Get(); + + Assert.AreEqual(3, res.Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(0)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(1)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(2)).GetNodes().Count); + + var prj = _grid1.GetCluster().ForPredicate(node => res.Take(2).Contains(node.Id)); + + Assert.AreEqual(2, prj.GetNodes().Count); + + var compute = prj.GetCompute().WithAsync(); + Assert.IsNull(compute.ExecuteJavaTask>(BroadcastTask, null)); + ICollection filteredRes = compute.GetFuture>().Get(); + + Assert.AreEqual(2, filteredRes.Count); + Assert.IsTrue(filteredRes.Contains(res.ElementAt(0))); + Assert.IsTrue(filteredRes.Contains(res.ElementAt(1))); + } + + /// + /// Tests the action broadcast. + /// + [Test] + public void TestBroadcastAction() + { + ComputeAction.InvokeCount = 0; + + _grid1.GetCompute().Broadcast(new ComputeAction()); + + Assert.AreEqual(_grid1.GetCluster().GetNodes().Count, ComputeAction.InvokeCount); + } + + /// + /// Tests single action run. + /// + [Test] + public void TestRunAction() + { + ComputeAction.InvokeCount = 0; + + _grid1.GetCompute().Run(new ComputeAction()); + + Assert.AreEqual(1, ComputeAction.InvokeCount); + } + + /// + /// Tests multiple actions run. + /// + [Test] + public void TestRunActions() + { + ComputeAction.InvokeCount = 0; + + var actions = Enumerable.Range(0, 10).Select(x => new ComputeAction()); + + _grid1.GetCompute().Run(actions); + + Assert.AreEqual(10, ComputeAction.InvokeCount); + } + + /// + /// Tests affinity run. + /// + [Test] + public void TestAffinityRun() + { + const string cacheName = null; + + // Test keys for non-client nodes + var nodes = new[] {_grid1, _grid2}.Select(x => x.GetCluster().GetLocalNode()); + + var aff = _grid1.GetAffinity(cacheName); + + foreach (var node in nodes) + { + var primaryKey = Enumerable.Range(1, int.MaxValue).First(x => aff.IsPrimary(node, x)); + + var affinityKey = _grid1.GetAffinity(cacheName).GetAffinityKey(primaryKey); + + _grid1.GetCompute().AffinityRun(cacheName, affinityKey, new ComputeAction()); + + Assert.AreEqual(node.Id, ComputeAction.LastNodeId); + } + } + + /// + /// Tests affinity call. + /// + [Test] + public void TestAffinityCall() + { + const string cacheName = null; + + // Test keys for non-client nodes + var nodes = new[] { _grid1, _grid2 }.Select(x => x.GetCluster().GetLocalNode()); + + var aff = _grid1.GetAffinity(cacheName); + + foreach (var node in nodes) + { + var primaryKey = Enumerable.Range(1, int.MaxValue).First(x => aff.IsPrimary(node, x)); + + var affinityKey = _grid1.GetAffinity(cacheName).GetAffinityKey(primaryKey); + + var result = _grid1.GetCompute().AffinityCall(cacheName, affinityKey, new ComputeFunc()); + + Assert.AreEqual(result, ComputeFunc.InvokeCount); + + Assert.AreEqual(node.Id, ComputeFunc.LastNodeId); + } + } + + /// + /// Test "withNoFailover" feature. + /// + [Test] + public void TestWithNoFailover() + { + ICollection res = _grid1.GetCompute().WithNoFailover().ExecuteJavaTask>(BroadcastTask, null); + + Assert.AreEqual(3, res.Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(0)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(1)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(2)).GetNodes().Count); + } + + /// + /// Test "withTimeout" feature. + /// + [Test] + public void TestWithTimeout() + { + ICollection res = _grid1.GetCompute().WithTimeout(1000).ExecuteJavaTask>(BroadcastTask, null); + + Assert.AreEqual(3, res.Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(0)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(1)).GetNodes().Count); + Assert.AreEqual(1, _grid1.GetCluster().ForNodeIds(res.ElementAt(2)).GetNodes().Count); + } + + /// + /// Test simple dotNet task execution. + /// + [Test] + public void TestNetTaskSimple() + { + int res = _grid1.GetCompute().Execute( + typeof(NetSimpleTask), new NetSimpleJobArgument(1)).Res; + + Assert.AreEqual(_grid1.GetCompute().ClusterGroup.GetNodes().Count, res); + } + + /// + /// Create configuration. + /// + /// XML config path. + private IgniteConfiguration Configuration(string path) + { + IgniteConfiguration cfg = new IgniteConfiguration(); + + PortableConfiguration portCfg = new PortableConfiguration(); + + ICollection portTypeCfgs = new List(); + + portTypeCfgs.Add(new PortableTypeConfiguration(typeof(PlatformComputePortable))); + portTypeCfgs.Add(new PortableTypeConfiguration(typeof(PlatformComputeNetPortable))); + portTypeCfgs.Add(new PortableTypeConfiguration(JavaPortableCls)); + + portCfg.TypeConfigurations = portTypeCfgs; + + cfg.PortableConfiguration = portCfg; + + cfg.JvmClasspath = IgniteManager.CreateClasspath(cfg, true); + + cfg.JvmOptions = TestUtils.TestJavaOptions(); + + cfg.SpringConfigUrl = path; + + return cfg; + } + } + + class PlatformComputePortable + { + public int Field + { + get; + set; + } + } + + class PlatformComputeNetPortable : PlatformComputePortable + { + + } + + [Serializable] + class NetSimpleTask : IComputeTask + { + /** */ + + public IDictionary, IClusterNode> Map(IList subgrid, + NetSimpleJobArgument arg) + { + var jobs = new Dictionary, IClusterNode>(); + + for (int i = 0; i < subgrid.Count; i++) + { + NetSimpleJob job = new NetSimpleJob {Arg = arg}; + + jobs[job] = subgrid[i]; + } + + return jobs; + } + + /** */ + public ComputeJobResultPolicy Result(IComputeJobResult res, + IList> rcvd) + { + return ComputeJobResultPolicy.Wait; + } + + /** */ + public NetSimpleTaskResult Reduce(IList> results) + { + return new NetSimpleTaskResult(results.Sum(res => res.Data().Res)); + } + } + + [Serializable] + class NetSimpleJob : IComputeJob + { + public NetSimpleJobArgument Arg; + + /** */ + public NetSimpleJobResult Execute() + { + return new NetSimpleJobResult(Arg.Arg); + } + + /** */ + public void Cancel() + { + // No-op. + } + } + + [Serializable] + class NetSimpleJobArgument + { + public int Arg; + + public NetSimpleJobArgument(int arg) + { + Arg = arg; + } + } + + [Serializable] + class NetSimpleTaskResult + { + public int Res; + + public NetSimpleTaskResult(int res) + { + Res = res; + } + } + + [Serializable] + class NetSimpleJobResult + { + public int Res; + + public NetSimpleJobResult(int res) + { + Res = res; + } + } + + [Serializable] + class ComputeAction : IComputeAction + { + [InstanceResource] + #pragma warning disable 649 + private IIgnite _grid; + + public static int InvokeCount; + + public static Guid LastNodeId; + + public void Invoke() + { + Interlocked.Increment(ref InvokeCount); + LastNodeId = _grid.GetCluster().GetLocalNode().Id; + } + } + + interface IUserInterface + { + T Invoke(); + } + + interface INestedComputeFunc : IComputeFunc + { + + } + + [Serializable] + class ComputeFunc : INestedComputeFunc, IUserInterface + { + [InstanceResource] + private IIgnite _grid; + + public static int InvokeCount; + + public static Guid LastNodeId; + + int IComputeFunc.Invoke() + { + InvokeCount++; + LastNodeId = _grid.GetCluster().GetLocalNode().Id; + return InvokeCount; + } + + int IUserInterface.Invoke() + { + // Same signature as IComputeFunc, but from different interface + throw new Exception("Invalid method"); + } + + public int Invoke() + { + // Same signature as IComputeFunc, but due to explicit interface implementation this is a wrong method + throw new Exception("Invalid method"); + } + } + + public enum InteropComputeEnum + { + Foo, + Bar, + Baz + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/65bb69da/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeMultithreadedTest.cs ---------------------------------------------------------------------- diff --git a/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeMultithreadedTest.cs b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeMultithreadedTest.cs new file mode 100644 index 0000000..5b6874f --- /dev/null +++ b/modules/platform/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeMultithreadedTest.cs @@ -0,0 +1,269 @@ +/* + * 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.Compute +{ + using System; + using System.Collections.Generic; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Compute; + using NUnit.Framework; + + /// + /// Tests class. + /// + [Category(TestUtils.CategoryIntensive)] + public class ComputeMultithreadedTest : AbstractTaskTest + { + /** */ + private static IList> _actions; + + /// + /// Constructor. + /// + public ComputeMultithreadedTest() : base(false) { } + + /// + /// Set-up routine. + /// + [SetUp] + public void SetUp() + { + _actions = new List> + { + compute => { compute.Apply(new My1ArgClosure(), "zzzz"); }, + compute => { compute.Broadcast(new My1ArgClosure(), "zzzz"); }, + compute => { compute.Broadcast(new MyNoArgClosure("zzzz")); }, + compute => { compute.Call(new MyNoArgClosure("zzzz")); }, + compute => { compute.Execute(new StringLengthEmptyTask(), "zzzz"); }, + compute => + { + compute.Apply(new My1ArgClosure(), new List {"zzzz", "a", "b"}, new MyReducer()); + } + }; + + } + + /// + /// Tear-down routine. + /// + [TearDown] + public void TearDown() + { + _actions.Clear(); + } + + /// + /// Test not-marshalable error occurred during map step. + /// + [Test] + public void TestAllTaskTypeAtSameTime() + { + Assert.AreEqual(_actions.Count, 6); + + var compute = Grid1.GetCompute(); + + TestUtils.RunMultiThreaded(() => + { + _actions[TestUtils.Random.Next(_actions.Count)](compute); + }, 4, 60); + } + + /// + /// + /// + [Test] + public void TestSingleTaskType0() + { + Assert.AreEqual(_actions.Count, 6); + + TestUtils.RunMultiThreaded(() => _actions[0](Grid1.GetCompute()), 4, 20); + } + + /// + /// + /// + [Test] + public void TestSingleTaskType1() + { + Assert.AreEqual(_actions.Count, 6); + + TestUtils.RunMultiThreaded(() => _actions[1](Grid1.GetCompute()), 4, 20); + } + + /// + /// + /// + [Test] + public void TestSingleTaskType2() + { + Assert.AreEqual(_actions.Count, 6); + + TestUtils.RunMultiThreaded(() => _actions[2](Grid1.GetCompute()), 4, 20); + } + + /// + /// + /// + [Test] + public void TestSingleTaskType3() + { + Assert.AreEqual(_actions.Count, 6); + + TestUtils.RunMultiThreaded(() => _actions[3](Grid1.GetCompute()), 4, 20); + } + /// + /// + /// + [Test] + public void TestSingleTaskType4() + { + Assert.AreEqual(_actions.Count, 6); + + TestUtils.RunMultiThreaded(() => _actions[4](Grid1.GetCompute()), 4, 20); + } + + /// + /// + /// + [Test] + public void TestSingleTaskType5() + { + Assert.AreEqual(_actions.Count, 6); + + TestUtils.RunMultiThreaded(() => _actions[5](Grid1.GetCompute()), 4, 20); + } + } + + /// + /// Test class. + /// + [Serializable] + public class My1ArgClosure : IComputeFunc + { + /** */ + public int Invoke(string s) + { + return s.Length; + } + } + + /// + /// Test class. + /// + [Serializable] + public class MyNoArgClosure : IComputeFunc + { + /** */ + private readonly string _s; + + /// + /// + /// + /// + public MyNoArgClosure(string s) + { + _s = s; + } + + /** */ + public int Invoke() + { + return _s.Length; + } + } + + /// + /// + /// + public class StringLengthEmptyTask : IComputeTask + { + /** */ + public IDictionary, IClusterNode> Map(IList subgrid, string arg) + { + var res = new Dictionary, IClusterNode>(); + + var job = new StringLengthEmptyJob(arg); + + IClusterNode node = subgrid[TestUtils.Random.Next(subgrid.Count)]; + + res.Add(job, node); + + return res; + } + + /** */ + public ComputeJobResultPolicy Result(IComputeJobResult res, IList> rcvd) + { + return ComputeJobResultPolicy.Wait; + } + + /** */ + public int Reduce(IList> results) + { + return results.Count == 0 ? 0 : results[0].Data(); + } + } + + /// + /// Test class. + /// + [Serializable] + public class StringLengthEmptyJob: IComputeJob + { + /** */ + private string _s; + + /// + /// + /// + /// + public StringLengthEmptyJob(string s) + { + _s = s; + } + + /** */ + public int Execute() + { + return _s.Length; + } + + /** */ + public void Cancel() + { + // No-op + } + } + + public class MyReducer : IComputeReducer + { + /** */ + private int _res; + + public bool Collect(int res) + { + _res += res; + return true; + } + + public int Reduce() + { + return _res; + } + } +}