blob: 6bea9b2d8e489d9a2f915a18946666c70b2a22de [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Apache.Ignite.Core.Tests.Services
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cluster;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Impl;
using Apache.Ignite.Core.Resource;
using Apache.Ignite.Core.Services;
using NUnit.Framework;
/// <summary>
/// Services tests.
/// </summary>
public class ServicesTest
{
/** */
private const string SvcName = "Service1";
/** */
private const string CacheName = "cache1";
/** */
private const int AffKey = 25;
/** */
protected IIgnite Grid1;
/** */
protected IIgnite Grid2;
/** */
protected IIgnite Grid3;
/** */
protected IIgnite[] Grids;
[TestFixtureTearDown]
public void FixtureTearDown()
{
StopGrids();
}
/// <summary>
/// Executes before each test.
/// </summary>
[SetUp]
public void SetUp()
{
StartGrids();
}
/// <summary>
/// Executes after each test.
/// </summary>
[TearDown]
public void TearDown()
{
try
{
Services.CancelAll();
TestUtils.AssertHandleRegistryIsEmpty(1000, Grid1, Grid2, Grid3);
}
catch (Exception)
{
// Restart grids to cleanup
StopGrids();
throw;
}
finally
{
if (TestContext.CurrentContext.Test.Name.StartsWith("TestEventTypes"))
StopGrids(); // clean events for other tests
}
}
/// <summary>
/// Tests deployment.
/// </summary>
[Test]
public void TestDeploy([Values(true, false)] bool binarizable)
{
var cfg = new ServiceConfiguration
{
Name = SvcName,
MaxPerNodeCount = 3,
TotalCount = 3,
NodeFilter = new NodeFilter {NodeId = Grid1.GetCluster().GetLocalNode().Id},
Service = binarizable ? new TestIgniteServiceBinarizable() : new TestIgniteServiceSerializable()
};
Services.Deploy(cfg);
CheckServiceStarted(Grid1, 3);
}
/// <summary>
/// Tests several services deployment via DeployAll() method.
/// </summary>
[Test]
public void TestDeployAll([Values(true, false)] bool binarizable)
{
const int num = 10;
var cfgs = new List<ServiceConfiguration>();
for (var i = 0; i < num; i++)
{
cfgs.Add(new ServiceConfiguration
{
Name = MakeServiceName(i),
MaxPerNodeCount = 3,
TotalCount = 3,
NodeFilter = new NodeFilter {NodeId = Grid1.GetCluster().GetLocalNode().Id},
Service = binarizable ? new TestIgniteServiceBinarizable() : new TestIgniteServiceSerializable()
});
}
Services.DeployAll(cfgs);
for (var i = 0; i < num; i++)
{
CheckServiceStarted(Grid1, 3, MakeServiceName(i));
}
}
/// <summary>
/// Tests cluster singleton deployment.
/// </summary>
[Test]
public void TestDeployClusterSingleton()
{
var svc = new TestIgniteServiceSerializable();
Services.DeployClusterSingleton(SvcName, svc);
var svc0 = Services.GetServiceProxy<ITestIgniteService>(SvcName);
// Check that only one node has the service.
foreach (var grid in Grids)
{
if (grid.GetCluster().GetLocalNode().Id == svc0.NodeId)
CheckServiceStarted(grid);
else
Assert.IsNull(grid.GetServices().GetService<TestIgniteServiceSerializable>(SvcName));
}
}
/// <summary>
/// Tests node singleton deployment.
/// </summary>
[Test]
public void TestDeployNodeSingleton()
{
var svc = new TestIgniteServiceSerializable();
Services.DeployNodeSingleton(SvcName, svc);
Assert.AreEqual(1, Grid1.GetServices().GetServices<ITestIgniteService>(SvcName).Count);
Assert.AreEqual(1, Grid2.GetServices().GetServices<ITestIgniteService>(SvcName).Count);
Assert.AreEqual(0, Grid3.GetServices().GetServices<ITestIgniteService>(SvcName).Count);
}
/// <summary>
/// Tests key affinity singleton deployment.
/// </summary>
[Test]
public void TestDeployKeyAffinitySingleton()
{
var svc = new TestIgniteServiceBinarizable();
Services.DeployKeyAffinitySingleton(SvcName, svc, CacheName, AffKey);
var affNode = Grid1.GetAffinity(CacheName).MapKeyToNode(AffKey);
var prx = Services.GetServiceProxy<ITestIgniteService>(SvcName);
Assert.AreEqual(affNode.Id, prx.NodeId);
}
/// <summary>
/// Tests key affinity singleton deployment.
/// </summary>
[Test]
public void TestDeployKeyAffinitySingletonBinarizable()
{
var services = Services.WithKeepBinary();
var svc = new TestIgniteServiceBinarizable();
var affKey = new BinarizableObject {Val = AffKey};
services.DeployKeyAffinitySingleton(SvcName, svc, CacheName, affKey);
var prx = services.GetServiceProxy<ITestIgniteService>(SvcName);
Assert.IsTrue(prx.Initialized);
}
/// <summary>
/// Tests multiple deployment.
/// </summary>
[Test]
public void TestDeployMultiple()
{
var svc = new TestIgniteServiceSerializable();
Services.DeployMultiple(SvcName, svc, Grids.Length * 5, 5);
foreach (var grid in Grids.Where(x => !x.GetConfiguration().ClientMode))
CheckServiceStarted(grid, 5);
}
/// <summary>
/// Tests cancellation.
/// </summary>
[Test]
public void TestCancel()
{
for (var i = 0; i < 10; i++)
{
Services.DeployNodeSingleton(SvcName + i, new TestIgniteServiceBinarizable());
Assert.IsNotNull(Services.GetService<ITestIgniteService>(SvcName + i));
}
Services.Cancel(SvcName + 0);
AssertNoService(SvcName + 0);
Services.Cancel(SvcName + 1);
AssertNoService(SvcName + 1);
for (var i = 2; i < 10; i++)
Assert.IsNotNull(Services.GetService<ITestIgniteService>(SvcName + i));
Services.CancelAll();
for (var i = 0; i < 10; i++)
AssertNoService(SvcName + i);
}
/// <summary>
/// Tests service proxy.
/// </summary>
[Test]
public void TestGetServiceProxy([Values(true, false)] bool binarizable)
{
// Test proxy without a service
var ex = Assert.Throws<IgniteException>(()=> Services.GetServiceProxy<ITestIgniteService>(SvcName));
Assert.AreEqual("Failed to find deployed service: " + SvcName, ex.Message);
// Deploy to grid2 & grid3
var svc = binarizable
? new TestIgniteServiceBinarizable {TestProperty = 17}
: new TestIgniteServiceSerializable {TestProperty = 17};
Grid1.GetCluster().ForNodeIds(Grid2.GetCluster().GetLocalNode().Id, Grid1.GetCluster().GetLocalNode().Id)
.GetServices().DeployNodeSingleton(SvcName, svc);
// Make sure there is no local instance on grid3
Assert.IsNull(Grid3.GetServices().GetService<ITestIgniteService>(SvcName));
// Get proxy
var prx = Grid3.GetServices().GetServiceProxy<ITestIgniteService>(SvcName);
// Check proxy properties
Assert.IsNotNull(prx);
Assert.AreEqual(prx.ToString(), svc.ToString());
Assert.AreEqual(17, prx.TestProperty);
Assert.IsTrue(prx.Initialized);
Assert.IsTrue(prx.Executed);
Assert.IsFalse(prx.Cancelled);
Assert.AreEqual(SvcName, prx.LastCallContextName);
// Check err method
Assert.Throws<ServiceInvocationException>(() => prx.ErrMethod(123));
// Check local scenario (proxy should not be created for local instance)
Assert.IsTrue(ReferenceEquals(Grid2.GetServices().GetService<ITestIgniteService>(SvcName),
Grid2.GetServices().GetServiceProxy<ITestIgniteService>(SvcName)));
// Check sticky = false: call multiple times, check that different nodes get invoked
var invokedIds = Enumerable.Range(1, 100).Select(x => prx.NodeId).Distinct().ToList();
Assert.AreEqual(2, invokedIds.Count);
// Check sticky = true: all calls should be to the same node
prx = Grid3.GetServices().GetServiceProxy<ITestIgniteService>(SvcName, true);
invokedIds = Enumerable.Range(1, 100).Select(x => prx.NodeId).Distinct().ToList();
Assert.AreEqual(1, invokedIds.Count);
// Proxy does not work for cancelled service.
Services.CancelAll();
Assert.Throws<ServiceInvocationException>(() => { Assert.IsTrue(prx.Cancelled); });
}
/// <summary>
/// Tests dynamic service proxies.
/// </summary>
[Test]
public void TestGetDynamicServiceProxy()
{
// Deploy to remotes.
var svc = new TestIgniteServiceSerializable { TestProperty = 37 };
Grid1.GetCluster().ForRemotes().GetServices().DeployNodeSingleton(SvcName, svc);
// Make sure there is no local instance on grid3
Assert.IsNull(Grid3.GetServices().GetService<ITestIgniteService>(SvcName));
// Get proxy.
dynamic prx = Grid3.GetServices().GetDynamicServiceProxy(SvcName, false);
// Property getter.
Assert.AreEqual(37, prx.TestProperty);
Assert.IsTrue(prx.Initialized);
Assert.IsTrue(prx.Executed);
Assert.IsFalse(prx.Cancelled);
Assert.AreEqual(SvcName, prx.LastCallContextName);
// Property setter.
prx.TestProperty = 42;
Assert.AreEqual(42, prx.TestProperty);
// Method invoke.
Assert.AreEqual(prx.ToString(), svc.ToString());
Assert.AreEqual("baz", prx.Method("baz"));
// Non-existent member.
var ex = Assert.Throws<ServiceInvocationException>(() => prx.FooBar(1));
Assert.AreEqual(
string.Format("Failed to invoke proxy: there is no method 'FooBar' in type '{0}' with 1 arguments",
typeof(TestIgniteServiceSerializable)), (ex.InnerException ?? ex).Message);
// Exception in service.
ex = Assert.Throws<ServiceInvocationException>(() => prx.ErrMethod(123));
Assert.AreEqual("ExpectedException", (ex.InnerException ?? ex).Message.Substring(0, 17));
}
/// <summary>
/// Tests dynamic service proxies with local service instance.
/// </summary>
[Test]
public void TestGetDynamicServiceProxyLocal()
{
// Deploy to all nodes.
var svc = new TestIgniteServiceSerializable { TestProperty = 37 };
Grid1.GetServices().DeployNodeSingleton(SvcName, svc);
// Make sure there is an instance on grid1.
var svcInst = Grid1.GetServices().GetService<ITestIgniteService>(SvcName);
Assert.IsNotNull(svcInst);
// Get dynamic proxy that simply wraps the service instance.
var prx = Grid1.GetServices().GetDynamicServiceProxy(SvcName);
Assert.AreSame(prx, svcInst);
}
/// <summary>
/// Tests the duck typing: proxy interface can be different from actual service interface,
/// only called method signature should be compatible.
/// </summary>
[Test]
public void TestDuckTyping([Values(true, false)] bool local)
{
var svc = new TestIgniteServiceBinarizable {TestProperty = 33};
// Deploy locally or to the remote node
var nodeId = (local ? Grid1 : Grid2).GetCluster().GetLocalNode().Id;
var cluster = Grid1.GetCluster().ForNodeIds(nodeId);
cluster.GetServices().DeployNodeSingleton(SvcName, svc);
// Get proxy
var prx = Services.GetServiceProxy<ITestIgniteServiceProxyInterface>(SvcName);
// NodeId signature is the same as in service
Assert.AreEqual(nodeId, prx.NodeId);
// Method signature is different from service signature (object -> object), but is compatible.
Assert.AreEqual(15, prx.Method(15));
// TestProperty is object in proxy and int in service, getter works..
Assert.AreEqual(33, prx.TestProperty);
// .. but setter does not
var ex = Assert.Throws<ServiceInvocationException>(() => { prx.TestProperty = new object(); });
Assert.IsInstanceOf<InvalidCastException>(ex.InnerException);
}
/// <summary>
/// Tests service descriptors.
/// </summary>
[Test]
public void TestServiceDescriptors()
{
Services.DeployKeyAffinitySingleton(SvcName, new TestIgniteServiceSerializable(), CacheName, 1);
var descriptors = Services.GetServiceDescriptors();
Assert.AreEqual(1, descriptors.Count);
var desc = descriptors.Single();
Assert.AreEqual(SvcName, desc.Name);
Assert.AreEqual(CacheName, desc.CacheName);
Assert.AreEqual(1, desc.AffinityKey);
Assert.AreEqual(1, desc.MaxPerNodeCount);
Assert.AreEqual(1, desc.TotalCount);
Assert.AreEqual(Grid1.GetCluster().GetLocalNode().Id, desc.OriginNodeId);
var top = desc.TopologySnapshot;
var prx = Services.GetServiceProxy<ITestIgniteService>(SvcName);
Assert.AreEqual(1, top.Count);
Assert.AreEqual(prx.NodeId, top.Keys.Single());
Assert.AreEqual(1, top.Values.Single());
}
/// <summary>
/// Tests the client binary flag.
/// </summary>
[Test]
public void TestWithKeepBinaryClient()
{
var svc = new TestIgniteServiceBinarizable();
// Deploy to grid2
Grid1.GetCluster().ForNodeIds(Grid2.GetCluster().GetLocalNode().Id).GetServices().WithKeepBinary()
.DeployNodeSingleton(SvcName, svc);
// Get proxy
var prx = Services.WithKeepBinary().GetServiceProxy<ITestIgniteService>(SvcName);
var obj = new BinarizableObject {Val = 11};
var res = (IBinaryObject) prx.Method(obj);
Assert.AreEqual(11, res.Deserialize<BinarizableObject>().Val);
res = (IBinaryObject) prx.Method(Grid1.GetBinary().ToBinary<IBinaryObject>(obj));
Assert.AreEqual(11, res.Deserialize<BinarizableObject>().Val);
}
/// <summary>
/// Tests the server binary flag.
/// </summary>
[Test]
public void TestWithKeepBinaryServer()
{
var svc = new TestIgniteServiceBinarizable();
// Deploy to grid2
Grid1.GetCluster().ForNodeIds(Grid2.GetCluster().GetLocalNode().Id).GetServices().WithServerKeepBinary()
.DeployNodeSingleton(SvcName, svc);
// Get proxy
var prx = Services.WithServerKeepBinary().GetServiceProxy<ITestIgniteService>(SvcName);
var obj = new BinarizableObject { Val = 11 };
var res = (BinarizableObject) prx.Method(obj);
Assert.AreEqual(11, res.Val);
res = (BinarizableObject)prx.Method(Grid1.GetBinary().ToBinary<IBinaryObject>(obj));
Assert.AreEqual(11, res.Val);
}
/// <summary>
/// Tests server and client binary flag.
/// </summary>
[Test]
public void TestWithKeepBinaryBoth()
{
var svc = new TestIgniteServiceBinarizable();
// Deploy to grid2
Grid1.GetCluster().ForNodeIds(Grid2.GetCluster().GetLocalNode().Id).GetServices().WithKeepBinary().WithServerKeepBinary()
.DeployNodeSingleton(SvcName, svc);
// Get proxy
var prx = Services.WithKeepBinary().WithServerKeepBinary().GetServiceProxy<ITestIgniteService>(SvcName);
var obj = new BinarizableObject { Val = 11 };
var res = (IBinaryObject)prx.Method(obj);
Assert.AreEqual(11, res.Deserialize<BinarizableObject>().Val);
res = (IBinaryObject)prx.Method(Grid1.GetBinary().ToBinary<IBinaryObject>(obj));
Assert.AreEqual(11, res.Deserialize<BinarizableObject>().Val);
}
/// <summary>
/// Tests exception in Initialize.
/// </summary>
[Test]
public void TestDeployMultipleException([Values(true, false)] bool keepBinary)
{
VerifyDeploymentException((services, svc) =>
services.DeployMultiple(SvcName, svc, Grids.Length, 1), keepBinary);
}
/// <summary>
/// Tests exception in Initialize.
/// </summary>
[Test]
public void TestDeployException([Values(true, false)] bool keepBinary)
{
VerifyDeploymentException((services, svc) =>
services.Deploy(new ServiceConfiguration
{
Name = SvcName,
Service = svc,
TotalCount = Grids.Length,
MaxPerNodeCount = 1
}), keepBinary);
}
/// <summary>
/// Tests ServiceDeploymentException result via DeployAll() method.
/// </summary>
[Test]
public void TestDeployAllException([Values(true, false)] bool binarizable)
{
const int num = 10;
const int firstFailedIdx = 1;
const int secondFailedIdx = 9;
var cfgs = new List<ServiceConfiguration>();
for (var i = 0; i < num; i++)
{
var throwInit = (i == firstFailedIdx || i == secondFailedIdx);
cfgs.Add(new ServiceConfiguration
{
Name = MakeServiceName(i),
MaxPerNodeCount = 2,
TotalCount = 2,
NodeFilter = new NodeFilter { NodeId = Grid1.GetCluster().GetLocalNode().Id },
Service = binarizable ? new TestIgniteServiceBinarizable { TestProperty = i, ThrowInit = throwInit }
: new TestIgniteServiceSerializable { TestProperty = i, ThrowInit = throwInit }
});
}
var deploymentException = Assert.Throws<ServiceDeploymentException>(() => Services.DeployAll(cfgs));
var failedCfgs = deploymentException.FailedConfigurations;
Assert.IsNotNull(failedCfgs);
Assert.AreEqual(2, failedCfgs.Count);
var firstFailedSvc = binarizable ? failedCfgs.ElementAt(0).Service as TestIgniteServiceBinarizable :
failedCfgs.ElementAt(0).Service as TestIgniteServiceSerializable;
var secondFailedSvc = binarizable ? failedCfgs.ElementAt(1).Service as TestIgniteServiceBinarizable :
failedCfgs.ElementAt(1).Service as TestIgniteServiceSerializable;
Assert.IsNotNull(firstFailedSvc);
Assert.IsNotNull(secondFailedSvc);
Assert.AreEqual(firstFailedIdx, firstFailedSvc.TestProperty);
Assert.AreEqual(secondFailedIdx, secondFailedSvc.TestProperty);
for (var i = 0; i < num; i++)
{
if (i != firstFailedIdx && i != secondFailedIdx)
{
CheckServiceStarted(Grid1, 2, MakeServiceName(i));
}
}
}
/// <summary>
/// Tests input errors for DeployAll() method.
/// </summary>
[Test]
public void TestDeployAllInputErrors()
{
var nullException = Assert.Throws<ArgumentNullException>(() => Services.DeployAll(null));
Assert.IsTrue(nullException.Message.Contains("configurations"));
var argException = Assert.Throws<ArgumentException>(() => Services.DeployAll(new List<ServiceConfiguration>()));
Assert.IsTrue(argException.Message.Contains("empty collection"));
nullException = Assert.Throws<ArgumentNullException>(() => Services.DeployAll(new List<ServiceConfiguration> { null }));
Assert.IsTrue(nullException.Message.Contains("configurations[0]"));
nullException = Assert.Throws<ArgumentNullException>(() => Services.DeployAll(new List<ServiceConfiguration>
{
new ServiceConfiguration { Name = SvcName }
}));
Assert.IsTrue(nullException.Message.Contains("configurations[0].Service"));
argException = Assert.Throws<ArgumentException>(() => Services.DeployAll(new List<ServiceConfiguration>
{
new ServiceConfiguration { Service = new TestIgniteServiceSerializable() }
}));
Assert.IsTrue(argException.Message.Contains("configurations[0].Name"));
argException = Assert.Throws<ArgumentException>(() => Services.DeployAll(new List<ServiceConfiguration>
{
new ServiceConfiguration { Service = new TestIgniteServiceSerializable(), Name = string.Empty }
}));
Assert.IsTrue(argException.Message.Contains("configurations[0].Name"));
}
/// <summary>
/// Tests [Serializable] usage of ServiceDeploymentException.
/// </summary>
[Test]
public void TestDeploymentExceptionSerializable()
{
var cfg = new ServiceConfiguration
{
Name = "foo",
CacheName = "cacheName",
AffinityKey = 1,
MaxPerNodeCount = 2,
Service = new TestIgniteServiceSerializable(),
NodeFilter = new NodeFilter(),
TotalCount = 3
};
var ex = new ServiceDeploymentException("msg", new Exception("in"), new[] {cfg});
var formatter = new BinaryFormatter();
var stream = new MemoryStream();
formatter.Serialize(stream, ex);
stream.Seek(0, SeekOrigin.Begin);
var res = (ServiceDeploymentException) formatter.Deserialize(stream);
Assert.AreEqual(ex.Message, res.Message);
Assert.IsNotNull(res.InnerException);
Assert.AreEqual("in", res.InnerException.Message);
var resCfg = res.FailedConfigurations.Single();
Assert.AreEqual(cfg.Name, resCfg.Name);
Assert.AreEqual(cfg.CacheName, resCfg.CacheName);
Assert.AreEqual(cfg.AffinityKey, resCfg.AffinityKey);
Assert.AreEqual(cfg.MaxPerNodeCount, resCfg.MaxPerNodeCount);
Assert.AreEqual(cfg.TotalCount, resCfg.TotalCount);
Assert.IsInstanceOf<TestIgniteServiceSerializable>(cfg.Service);
Assert.IsInstanceOf<NodeFilter>(cfg.NodeFilter);
}
/// <summary>
/// Verifies the deployment exception.
/// </summary>
private void VerifyDeploymentException(Action<IServices, IService> deploy, bool keepBinary)
{
var svc = new TestIgniteServiceSerializable { ThrowInit = true };
var services = Services;
if (keepBinary)
{
services = services.WithKeepBinary();
}
var deploymentException = Assert.Throws<ServiceDeploymentException>(() => deploy(services, svc));
var text = keepBinary
? "Service deployment failed with a binary error. Examine BinaryCause for details."
: "Service deployment failed with an exception. Examine InnerException for details.";
Assert.AreEqual(text, deploymentException.Message);
Exception ex;
if (keepBinary)
{
Assert.IsNull(deploymentException.InnerException);
ex = deploymentException.BinaryCause.Deserialize<Exception>();
}
else
{
Assert.IsNull(deploymentException.BinaryCause);
ex = deploymentException.InnerException;
}
Assert.IsNotNull(ex);
Assert.AreEqual("Expected exception", ex.Message);
Assert.IsTrue(ex.StackTrace.Trim().StartsWith(
"at Apache.Ignite.Core.Tests.Services.ServicesTest.TestIgniteServiceSerializable.Init"));
var failedCfgs = deploymentException.FailedConfigurations;
Assert.IsNotNull(failedCfgs);
Assert.AreEqual(1, failedCfgs.Count);
var svc0 = Services.GetService<TestIgniteServiceSerializable>(SvcName);
Assert.IsNull(svc0);
}
/// <summary>
/// Tests exception in Execute.
/// </summary>
[Test]
public void TestExecuteException()
{
var svc = new TestIgniteServiceSerializable { ThrowExecute = true };
Services.DeployMultiple(SvcName, svc, Grids.Length, 1);
var svc0 = Services.GetService<TestIgniteServiceSerializable>(SvcName);
// Execution failed, but service exists.
Assert.IsNotNull(svc0);
Assert.IsFalse(svc0.Executed);
}
/// <summary>
/// Tests exception in Cancel.
/// </summary>
[Test]
public void TestCancelException()
{
var svc = new TestIgniteServiceSerializable { ThrowCancel = true };
Services.DeployMultiple(SvcName, svc, 2, 1);
CheckServiceStarted(Grid1);
Services.CancelAll();
// Cancellation failed, but service is removed.
AssertNoService();
}
/// <summary>
/// Tests exception in binarizable implementation.
/// </summary>
[Test]
public void TestMarshalExceptionOnRead()
{
var svc = new TestIgniteServiceBinarizableErr();
var ex = Assert.Throws<ServiceDeploymentException>(() =>
Services.DeployMultiple(SvcName, svc, Grids.Length, 1));
Assert.IsNotNull(ex.InnerException);
Assert.AreEqual("Expected exception", ex.InnerException.Message);
var svc0 = Services.GetService<TestIgniteServiceSerializable>(SvcName);
Assert.IsNull(svc0);
}
/// <summary>
/// Tests exception in binarizable implementation.
/// </summary>
[Test]
public void TestMarshalExceptionOnWrite()
{
var svc = new TestIgniteServiceBinarizableErr {ThrowOnWrite = true};
var ex = Assert.Throws<Exception>(() => Services.DeployMultiple(SvcName, svc, Grids.Length, 1));
Assert.AreEqual("Expected exception", ex.Message);
var svc0 = Services.GetService<TestIgniteServiceSerializable>(SvcName);
Assert.IsNull(svc0);
}
/// <summary>
/// Tests Java service invocation.
/// </summary>
[Test]
public void TestCallJavaService()
{
// Deploy Java service
const string javaSvcName = "javaService";
DeployJavaService(javaSvcName);
// Verify decriptor
var descriptor = Services.GetServiceDescriptors().Single(x => x.Name == javaSvcName);
Assert.AreEqual(javaSvcName, descriptor.Name);
var svc = Services.GetServiceProxy<IJavaService>(javaSvcName, false);
var binSvc = Services.WithKeepBinary().WithServerKeepBinary()
.GetServiceProxy<IJavaService>(javaSvcName, false);
// Basics
Assert.IsTrue(svc.isInitialized());
Assert.IsTrue(TestUtils.WaitForCondition(() => svc.isExecuted(), 500));
Assert.IsFalse(svc.isCancelled());
// Primitives
Assert.AreEqual(4, svc.test((byte) 3));
Assert.AreEqual(5, svc.test((short) 4));
Assert.AreEqual(6, svc.test(5));
Assert.AreEqual(6, svc.test((long) 5));
Assert.AreEqual(3.8f, svc.test(2.3f));
Assert.AreEqual(5.8, svc.test(3.3));
Assert.IsFalse(svc.test(true));
Assert.AreEqual('b', svc.test('a'));
Assert.AreEqual("Foo!", svc.test("Foo"));
// Nullables (Java wrapper types)
Assert.AreEqual(4, svc.testWrapper(3));
Assert.AreEqual(5, svc.testWrapper((short?) 4));
Assert.AreEqual(6, svc.testWrapper((int?)5));
Assert.AreEqual(6, svc.testWrapper((long?) 5));
Assert.AreEqual(3.8f, svc.testWrapper(2.3f));
Assert.AreEqual(5.8, svc.testWrapper(3.3));
Assert.AreEqual(false, svc.testWrapper(true));
Assert.AreEqual('b', svc.testWrapper('a'));
// Arrays
Assert.AreEqual(new byte[] {2, 3, 4}, svc.testArray(new byte[] {1, 2, 3}));
Assert.AreEqual(new short[] {2, 3, 4}, svc.testArray(new short[] {1, 2, 3}));
Assert.AreEqual(new[] {2, 3, 4}, svc.testArray(new[] {1, 2, 3}));
Assert.AreEqual(new long[] {2, 3, 4}, svc.testArray(new long[] {1, 2, 3}));
Assert.AreEqual(new float[] {2, 3, 4}, svc.testArray(new float[] {1, 2, 3}));
Assert.AreEqual(new double[] {2, 3, 4}, svc.testArray(new double[] {1, 2, 3}));
Assert.AreEqual(new[] {"a1", "b1"}, svc.testArray(new [] {"a", "b"}));
Assert.AreEqual(new[] {'c', 'd'}, svc.testArray(new[] {'b', 'c'}));
Assert.AreEqual(new[] {false, true, false}, svc.testArray(new[] {true, false, true}));
// Nulls
Assert.AreEqual(9, svc.testNull(8));
Assert.IsNull(svc.testNull(null));
// params / varargs
Assert.AreEqual(5, svc.testParams(1, 2, 3, 4, "5"));
Assert.AreEqual(0, svc.testParams());
// Overloads
Assert.AreEqual(3, svc.test(2, "1"));
Assert.AreEqual(3, svc.test("1", 2));
// Binary
Assert.AreEqual(7, svc.testBinarizable(new PlatformComputeBinarizable {Field = 6}).Field);
// Binary collections
var arr = new [] {10, 11, 12}.Select(x => new PlatformComputeBinarizable {Field = x}).ToArray<object>();
Assert.AreEqual(new[] {11, 12, 13}, svc.testBinarizableCollection(arr)
.OfType<PlatformComputeBinarizable>().Select(x => x.Field).ToArray());
Assert.AreEqual(new[] {11, 12, 13},
svc.testBinarizableArray(arr).OfType<PlatformComputeBinarizable>().Select(x => x.Field).ToArray());
// Binary object
Assert.AreEqual(15,
binSvc.testBinaryObject(
Grid1.GetBinary().ToBinary<IBinaryObject>(new PlatformComputeBinarizable {Field = 6}))
.GetField<int>("Field"));
Services.Cancel(javaSvcName);
}
/// <summary>
/// Tests Java service invocation with dynamic proxy.
/// </summary>
[Test]
public void TestCallJavaServiceDynamicProxy()
{
const string javaSvcName = "javaService";
DeployJavaService(javaSvcName);
var svc = Grid1.GetServices().GetDynamicServiceProxy(javaSvcName, true);
// Basics
Assert.IsTrue(svc.isInitialized());
Assert.IsTrue(TestUtils.WaitForCondition(() => svc.isExecuted(), 500));
Assert.IsFalse(svc.isCancelled());
// Primitives
Assert.AreEqual(4, svc.test((byte)3));
Assert.AreEqual(5, svc.test((short)4));
Assert.AreEqual(6, svc.test(5));
Assert.AreEqual(6, svc.test((long)5));
Assert.AreEqual(3.8f, svc.test(2.3f));
Assert.AreEqual(5.8, svc.test(3.3));
Assert.IsFalse(svc.test(true));
Assert.AreEqual('b', svc.test('a'));
Assert.AreEqual("Foo!", svc.test("Foo"));
// Nullables (Java wrapper types)
Assert.AreEqual(4, svc.testWrapper(3));
Assert.AreEqual(5, svc.testWrapper((short?)4));
Assert.AreEqual(6, svc.testWrapper((int?)5));
Assert.AreEqual(6, svc.testWrapper((long?)5));
Assert.AreEqual(3.8f, svc.testWrapper(2.3f));
Assert.AreEqual(5.8, svc.testWrapper(3.3));
Assert.AreEqual(false, svc.testWrapper(true));
Assert.AreEqual('b', svc.testWrapper('a'));
// Arrays
Assert.AreEqual(new byte[] { 2, 3, 4 }, svc.testArray(new byte[] { 1, 2, 3 }));
Assert.AreEqual(new short[] { 2, 3, 4 }, svc.testArray(new short[] { 1, 2, 3 }));
Assert.AreEqual(new[] { 2, 3, 4 }, svc.testArray(new[] { 1, 2, 3 }));
Assert.AreEqual(new long[] { 2, 3, 4 }, svc.testArray(new long[] { 1, 2, 3 }));
Assert.AreEqual(new float[] { 2, 3, 4 }, svc.testArray(new float[] { 1, 2, 3 }));
Assert.AreEqual(new double[] { 2, 3, 4 }, svc.testArray(new double[] { 1, 2, 3 }));
Assert.AreEqual(new[] { "a1", "b1" }, svc.testArray(new[] { "a", "b" }));
Assert.AreEqual(new[] { 'c', 'd' }, svc.testArray(new[] { 'b', 'c' }));
Assert.AreEqual(new[] { false, true, false }, svc.testArray(new[] { true, false, true }));
// Nulls
Assert.AreEqual(9, svc.testNull(8));
Assert.IsNull(svc.testNull(null));
// Overloads
Assert.AreEqual(3, svc.test(2, "1"));
Assert.AreEqual(3, svc.test("1", 2));
// Binary
Assert.AreEqual(7, svc.testBinarizable(new PlatformComputeBinarizable { Field = 6 }).Field);
// Binary object
var binSvc = Services.WithKeepBinary().WithServerKeepBinary().GetDynamicServiceProxy(javaSvcName);
Assert.AreEqual(15,
binSvc.testBinaryObject(
Grid1.GetBinary().ToBinary<IBinaryObject>(new PlatformComputeBinarizable { Field = 6 }))
.GetField<int>("Field"));
}
/// <summary>
/// Deploys the java service.
/// </summary>
private void DeployJavaService(string javaSvcName)
{
Grid1.GetCompute()
.ExecuteJavaTask<object>("org.apache.ignite.platform.PlatformDeployServiceTask", javaSvcName);
TestUtils.WaitForCondition(() => Services.GetServiceDescriptors().Any(x => x.Name == javaSvcName), 1000);
}
/// <summary>
/// Tests the footer setting.
/// </summary>
[Test]
public void TestFooterSetting()
{
foreach (var grid in Grids)
{
Assert.AreEqual(CompactFooter, ((Ignite) grid).Marshaller.CompactFooter);
Assert.AreEqual(CompactFooter, grid.GetConfiguration().BinaryConfiguration.CompactFooter);
}
}
/// <summary>
/// Starts the grids.
/// </summary>
private void StartGrids()
{
if (Grid1 != null)
return;
Grid1 = Ignition.Start(GetConfiguration("Config\\Compute\\compute-grid1.xml"));
Grid2 = Ignition.Start(GetConfiguration("Config\\Compute\\compute-grid2.xml"));
Grid3 = Ignition.Start(GetConfiguration("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>
/// Checks that service has started on specified grid.
/// </summary>
private static void CheckServiceStarted(IIgnite grid, int count = 1, string svcName = SvcName)
{
Func<ICollection<TestIgniteServiceSerializable>> getServices = () =>
grid.GetServices().GetServices<TestIgniteServiceSerializable>(svcName);
Assert.IsTrue(TestUtils.WaitForCondition(() => count == getServices().Count, 5000));
var svc = getServices().First();
Assert.IsNotNull(svc);
Assert.IsTrue(svc.Initialized);
Thread.Sleep(100); // Service runs in a separate thread, wait for it to execute.
Assert.IsTrue(svc.Executed);
Assert.IsFalse(svc.Cancelled);
Assert.AreEqual(grid.GetCluster().GetLocalNode().Id, svc.NodeId);
}
/// <summary>
/// Gets the Ignite configuration.
/// </summary>
private IgniteConfiguration GetConfiguration(string springConfigUrl)
{
#if !NETCOREAPP2_0 && !NETCOREAPP2_1
if (!CompactFooter)
{
springConfigUrl = Compute.ComputeApiTestFullFooter.ReplaceFooterSetting(springConfigUrl);
}
#endif
return new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
SpringConfigUrl = springConfigUrl,
BinaryConfiguration = new BinaryConfiguration(
typeof (TestIgniteServiceBinarizable),
typeof (TestIgniteServiceBinarizableErr),
typeof (PlatformComputeBinarizable),
typeof (BinarizableObject))
{
NameMapper = BinaryBasicNameMapper.SimpleNameInstance
}
};
}
/// <summary>
/// Asserts that there is no service on any grid with given name.
/// </summary>
/// <param name="name">The name.</param>
private void AssertNoService(string name = SvcName)
{
foreach (var grid in Grids)
Assert.IsTrue(
// ReSharper disable once AccessToForEachVariableInClosure
TestUtils.WaitForCondition(() => grid.GetServices()
.GetService<ITestIgniteService>(name) == null, 5000));
}
/// <summary>
/// Gets the services.
/// </summary>
protected virtual IServices Services
{
get { return Grid1.GetServices(); }
}
/// <summary>
/// Gets a value indicating whether compact footers should be used.
/// </summary>
protected virtual bool CompactFooter { get { return true; } }
/// <summary>
/// Makes Service1-{i} names for services.
/// </summary>
private static string MakeServiceName(int i)
{
// Please note that CheckContext() validates Name.StartsWith(SvcName).
return string.Format("{0}-{1}", SvcName, i);
}
/// <summary>
/// Test base service.
/// </summary>
public interface ITestIgniteServiceBase
{
/** */
int TestProperty { get; set; }
/** */
object Method(object arg);
}
/// <summary>
/// Test service interface for proxying.
/// </summary>
public interface ITestIgniteService : IService, ITestIgniteServiceBase
{
/** */
bool Initialized { get; }
/** */
bool Cancelled { get; }
/** */
bool Executed { get; }
/** */
Guid NodeId { get; }
/** */
string LastCallContextName { get; }
/** */
object ErrMethod(object arg);
}
/// <summary>
/// Test service interface for proxy usage.
/// Has some of the original interface members with different signatures.
/// </summary>
public interface ITestIgniteServiceProxyInterface
{
/** */
Guid NodeId { get; }
/** */
object TestProperty { get; set; }
/** */
int Method(int arg);
}
#pragma warning disable 649
/// <summary>
/// Test serializable service.
/// </summary>
[Serializable]
private class TestIgniteServiceSerializable : ITestIgniteService
{
/** */
[InstanceResource]
private IIgnite _grid;
/** <inheritdoc /> */
public int TestProperty { get; set; }
/** <inheritdoc /> */
public bool Initialized { get; private set; }
/** <inheritdoc /> */
public bool Cancelled { get; private set; }
/** <inheritdoc /> */
public bool Executed { get; private set; }
/** <inheritdoc /> */
public Guid NodeId
{
// ReSharper disable once InconsistentlySynchronizedField
get { return _grid.GetCluster().GetLocalNode().Id; }
}
/** <inheritdoc /> */
public string LastCallContextName { get; private set; }
/** */
public bool ThrowInit { get; set; }
/** */
public bool ThrowExecute { get; set; }
/** */
public bool ThrowCancel { get; set; }
/** */
public object Method(object arg)
{
return arg;
}
/** */
public object ErrMethod(object arg)
{
throw new ArgumentNullException("arg", "ExpectedException");
}
/** <inheritdoc /> */
public void Init(IServiceContext context)
{
lock (this)
{
if (ThrowInit)
throw new Exception("Expected exception");
CheckContext(context);
Assert.IsFalse(context.IsCancelled);
Initialized = true;
}
}
/** <inheritdoc /> */
public void Execute(IServiceContext context)
{
lock (this)
{
if (ThrowExecute)
throw new Exception("Expected exception");
CheckContext(context);
Assert.IsFalse(context.IsCancelled);
Assert.IsTrue(Initialized);
Assert.IsFalse(Cancelled);
Executed = true;
}
}
/** <inheritdoc /> */
public void Cancel(IServiceContext context)
{
lock (this)
{
if (ThrowCancel)
throw new Exception("Expected exception");
CheckContext(context);
Assert.IsTrue(context.IsCancelled);
Cancelled = true;
}
}
/// <summary>
/// Checks the service context.
/// </summary>
private void CheckContext(IServiceContext context)
{
LastCallContextName = context.Name;
if (context.AffinityKey != null && !(context.AffinityKey is int))
{
var binaryObj = context.AffinityKey as IBinaryObject;
var key = binaryObj != null
? binaryObj.Deserialize<BinarizableObject>()
: (BinarizableObject) context.AffinityKey;
Assert.AreEqual(AffKey, key.Val);
}
Assert.IsNotNull(_grid);
Assert.IsTrue(context.Name.StartsWith(SvcName));
Assert.AreNotEqual(Guid.Empty, context.ExecutionId);
}
}
/// <summary>
/// Test binary service.
/// </summary>
private class TestIgniteServiceBinarizable : TestIgniteServiceSerializable, IBinarizable
{
/** <inheritdoc /> */
public void WriteBinary(IBinaryWriter writer)
{
writer.WriteInt("TestProp", TestProperty);
writer.WriteBoolean("ThrowInit", ThrowInit);
}
/** <inheritdoc /> */
public void ReadBinary(IBinaryReader reader)
{
ThrowInit = reader.ReadBoolean("ThrowInit");
TestProperty = reader.ReadInt("TestProp");
}
}
/// <summary>
/// Test binary service with exceptions in marshalling.
/// </summary>
private class TestIgniteServiceBinarizableErr : TestIgniteServiceSerializable, IBinarizable
{
/** */
public bool ThrowOnWrite { get; set; }
/** <inheritdoc /> */
public void WriteBinary(IBinaryWriter writer)
{
writer.WriteInt("TestProp", TestProperty);
if (ThrowOnWrite)
throw new Exception("Expected exception");
}
/** <inheritdoc /> */
public void ReadBinary(IBinaryReader reader)
{
TestProperty = reader.ReadInt("TestProp");
throw new Exception("Expected exception");
}
}
/// <summary>
/// Test node filter.
/// </summary>
[Serializable]
private class NodeFilter : IClusterNodeFilter
{
/// <summary>
/// Gets or sets the node identifier.
/// </summary>
public Guid NodeId { get; set; }
/** <inheritdoc /> */
public bool Invoke(IClusterNode node)
{
return node.Id == NodeId;
}
}
/// <summary>
/// Binary object.
/// </summary>
private class BinarizableObject
{
public int Val { get; set; }
}
/// <summary>
/// Java service proxy interface.
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public interface IJavaService
{
/** */
bool isCancelled();
/** */
bool isInitialized();
/** */
bool isExecuted();
/** */
byte test(byte x);
/** */
short test(short x);
/** */
int test(int x);
/** */
long test(long x);
/** */
float test(float x);
/** */
double test(double x);
/** */
char test(char x);
/** */
string test(string x);
/** */
bool test(bool x);
/** */
byte? testWrapper(byte? x);
/** */
short? testWrapper(short? x);
/** */
int? testWrapper(int? x);
/** */
long? testWrapper(long? x);
/** */
float? testWrapper(float? x);
/** */
double? testWrapper(double? x);
/** */
char? testWrapper(char? x);
/** */
bool? testWrapper(bool? x);
/** */
byte[] testArray(byte[] x);
/** */
short[] testArray(short[] x);
/** */
int[] testArray(int[] x);
/** */
long[] testArray(long[] x);
/** */
float[] testArray(float[] x);
/** */
double[] testArray(double[] x);
/** */
char[] testArray(char[] x);
/** */
string[] testArray(string[] x);
/** */
bool[] testArray(bool[] x);
/** */
int test(int x, string y);
/** */
int test(string x, int y);
/** */
int? testNull(int? x);
/** */
int testParams(params object[] args);
/** */
PlatformComputeBinarizable testBinarizable(PlatformComputeBinarizable x);
/** */
object[] testBinarizableArray(object[] x);
/** */
ICollection testBinarizableCollection(ICollection x);
/** */
IBinaryObject testBinaryObject(IBinaryObject x);
}
/// <summary>
/// Interop class.
/// </summary>
public class PlatformComputeBinarizable
{
/** */
public int Field { get; set; }
}
}
}