| /* |
| * 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. |
| */ |
| |
| #if !NETCOREAPP |
| // ReSharper disable UnusedVariable |
| // ReSharper disable UnusedAutoPropertyAccessor.Global |
| // ReSharper disable UnusedAutoPropertyAccessor.Local |
| namespace Apache.Ignite.Core.Tests |
| { |
| using System; |
| using System.CodeDom.Compiler; |
| using System.Collections.Generic; |
| using System.IO; |
| using System.Linq; |
| using Apache.Ignite.Core.Binary; |
| using Apache.Ignite.Core.Compute; |
| using Apache.Ignite.Core.Impl; |
| using Apache.Ignite.Core.Resource; |
| using Apache.Ignite.Core.Tests.Process; |
| using NUnit.Framework; |
| |
| /// <summary> |
| /// Tests for Apache.Ignite.exe. |
| /// </summary> |
| [Category(TestUtils.CategoryIntensive)] |
| public class ExecutableTest |
| { |
| /** Spring configuration path. */ |
| private const string SpringCfgPath = "Config/Compute/compute-standalone.xml"; |
| |
| /** Min memory Java task. */ |
| private const string MinMemTask = "org.apache.ignite.platform.PlatformMinMemoryTask"; |
| |
| /** Max memory Java task. */ |
| private const string MaxMemTask = "org.apache.ignite.platform.PlatformMaxMemoryTask"; |
| |
| /** Grid. */ |
| private IIgnite _grid; |
| |
| /** Temp dir for assemblies. */ |
| private string _tempDir; |
| |
| /// <summary> |
| /// Set-up routine. |
| /// </summary> |
| [SetUp] |
| public void SetUp() |
| { |
| _tempDir = PathUtils.GetTempDirectoryName(); |
| |
| TestUtils.KillProcesses(); |
| |
| _grid = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) |
| { |
| BinaryConfiguration = new BinaryConfiguration |
| { |
| TypeConfigurations = new List<BinaryTypeConfiguration> |
| { |
| new BinaryTypeConfiguration(typeof(RemoteConfiguration)), |
| new BinaryTypeConfiguration(typeof(RemoteConfigurationClosure)) |
| } |
| }, |
| SpringConfigUrl = SpringCfgPath |
| }); |
| |
| Assert.IsTrue(_grid.WaitTopology(1)); |
| |
| IgniteProcess.SaveConfigurationBackup(); |
| } |
| |
| /// <summary> |
| /// Tear-down routine. |
| /// </summary> |
| [TearDown] |
| public void TearDown() |
| { |
| Ignition.StopAll(true); |
| |
| TestUtils.KillProcesses(); |
| |
| IgniteProcess.RestoreConfigurationBackup(); |
| |
| Directory.Delete(_tempDir, true); |
| } |
| |
| /// <summary> |
| /// Test data pass through configuration file. |
| /// </summary> |
| [Test] |
| public void TestConfig() |
| { |
| IgniteProcess.ReplaceConfiguration("config\\Apache.Ignite.exe.config.test"); |
| |
| GenerateDll("test-1.dll"); |
| GenerateDll("test-2.dll"); |
| |
| var proc = new IgniteProcess(); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var cfg = RemoteConfig(); |
| |
| Assert.AreEqual(SpringCfgPath, cfg.SpringConfigUrl); |
| Assert.AreEqual(602, cfg.JvmInitialMemoryMb); |
| Assert.AreEqual(702, cfg.JvmMaxMemoryMb); |
| |
| CollectionAssert.Contains(cfg.LoadedAssemblies, "test-1"); |
| CollectionAssert.Contains(cfg.LoadedAssemblies, "test-2"); |
| Assert.Null(cfg.Assemblies); |
| |
| CollectionAssert.Contains(cfg.JvmOptions, "-DOPT1"); |
| CollectionAssert.Contains(cfg.JvmOptions, "-DOPT2"); |
| } |
| |
| /// <summary> |
| /// Test assemblies passing through command-line. |
| /// </summary> |
| [Test] |
| public void TestAssemblyCmd() |
| { |
| var dll1 = GenerateDll("test-1.dll", true); |
| var dll2 = GenerateDll("test-2.dll", true); |
| |
| var proc = new IgniteProcess( |
| "-springConfigUrl=" + SpringCfgPath, |
| "-assembly=" + dll1, |
| "-assembly=" + dll2); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var cfg = RemoteConfig(); |
| |
| CollectionAssert.Contains(cfg.LoadedAssemblies, "test-1"); |
| CollectionAssert.Contains(cfg.LoadedAssemblies, "test-2"); |
| } |
| |
| /// <summary> |
| /// Test JVM options passing through command-line. |
| /// </summary> |
| [Test] |
| public void TestJvmOptsCmd() |
| { |
| var proc = new IgniteProcess( |
| "-springConfigUrl=" + SpringCfgPath, |
| "-J-DOPT1", |
| "-J-DOPT2" |
| ); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var cfg = RemoteConfig(); |
| |
| Assert.IsTrue(cfg.JvmOptions.Contains("-DOPT1") && cfg.JvmOptions.Contains("-DOPT2")); |
| } |
| |
| /// <summary> |
| /// Test JVM memory options passing through command-line: raw java options. |
| /// </summary> |
| [Test] |
| public void TestJvmMemoryOptsCmdRaw() |
| { |
| var proc = new IgniteProcess( |
| "-springConfigUrl=" + SpringCfgPath, |
| "-J-Xms506m", |
| "-J-Xmx607m" |
| ); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var minMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MinMemTask, null); |
| Assert.AreEqual((long) 506*1024*1024, minMem); |
| |
| var maxMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MaxMemTask, null); |
| AssertJvmMaxMemory((long) 607*1024*1024, maxMem); |
| } |
| |
| /// <summary> |
| /// Test JVM memory options passing through command-line: custom options. |
| /// </summary> |
| [Test] |
| public void TestJvmMemoryOptsCmdCustom() |
| { |
| var proc = new IgniteProcess( |
| "-springConfigUrl=" + SpringCfgPath, |
| "-JvmInitialMemoryMB=616", |
| "-JvmMaxMemoryMB=866" |
| ); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var minMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MinMemTask, null); |
| Assert.AreEqual((long) 616*1024*1024, minMem); |
| |
| var maxMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MaxMemTask, null); |
| AssertJvmMaxMemory((long) 866*1024*1024, maxMem); |
| } |
| |
| /// <summary> |
| /// Test JVM memory options passing from application configuration. |
| /// </summary> |
| [Test] |
| public void TestJvmMemoryOptsAppConfig( |
| [Values("config\\Apache.Ignite.exe.config.test", "config\\Apache.Ignite.exe.config.test2")] string config) |
| { |
| IgniteProcess.ReplaceConfiguration(config); |
| |
| GenerateDll("test-1.dll"); |
| GenerateDll("test-2.dll"); |
| |
| var proc = new IgniteProcess(); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var minMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MinMemTask, null); |
| Assert.AreEqual((long) 602*1024*1024, minMem); |
| |
| var maxMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MaxMemTask, null); |
| AssertJvmMaxMemory((long) 702*1024*1024, maxMem); |
| |
| proc.Kill(); |
| |
| Assert.IsTrue(_grid.WaitTopology(1)); |
| |
| // Command line options overwrite config file options |
| // ReSharper disable once RedundantAssignment |
| proc = new IgniteProcess("-J-Xms606m", "-J-Xmx706m"); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| minMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MinMemTask, null); |
| Assert.AreEqual((long) 606*1024*1024, minMem); |
| |
| maxMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MaxMemTask, null); |
| AssertJvmMaxMemory((long) 706*1024*1024, maxMem); |
| } |
| |
| /// <summary> |
| /// Test JVM memory options passing through command-line: custom options + raw options. |
| /// </summary> |
| [Test] |
| public void TestJvmMemoryOptsCmdCombined() |
| { |
| var proc = new IgniteProcess( |
| "-springConfigUrl=" + SpringCfgPath, |
| "-J-Xms556m", |
| "-J-Xmx666m", |
| "-JvmInitialMemoryMB=128", |
| "-JvmMaxMemoryMB=256" |
| ); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| // Raw JVM options (Xms/Xmx) should override custom options |
| var minMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MinMemTask, null); |
| Assert.AreEqual((long) 556*1024*1024, minMem); |
| |
| var maxMem = _grid.GetCluster().ForRemotes().GetCompute().ExecuteJavaTask<long>(MaxMemTask, null); |
| AssertJvmMaxMemory((long) 666*1024*1024, maxMem); |
| } |
| |
| /// <summary> |
| /// Tests the .NET XML configuration specified in app.config. |
| /// </summary> |
| [Test] |
| public void TestXmlConfigurationAppConfig() |
| { |
| IgniteProcess.ReplaceConfiguration("config\\Apache.Ignite.exe.config.test3"); |
| |
| var proc = new IgniteProcess(); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var remoteCfg = RemoteConfig(); |
| Assert.IsTrue(remoteCfg.JvmOptions.Contains("-DOPT25")); |
| |
| proc.Kill(); |
| |
| Assert.IsTrue(_grid.WaitTopology(1)); |
| } |
| |
| /// <summary> |
| /// Tests the .NET XML configuration specified in command line. |
| /// </summary> |
| [Test] |
| public void TestXmlConfigurationCmd() |
| { |
| var proc = new IgniteProcess("-configFileName=config\\ignite-dotnet-cfg.xml"); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var remoteCfg = RemoteConfig(); |
| Assert.IsTrue(remoteCfg.JvmOptions.Contains("-DOPT25")); |
| |
| proc.Kill(); |
| |
| Assert.IsTrue(_grid.WaitTopology(1)); |
| } |
| |
| /// <summary> |
| /// Tests invalid command arguments. |
| /// </summary> |
| [Test] |
| public void TestInvalidCmdArgs() |
| { |
| var ignoredWarns = new[] |
| { |
| "WARNING: An illegal reflective access operation has occurred", |
| "WARNING: Illegal reflective access by org.apache.ignite.internal.util.GridUnsafe$2 " + |
| "(file:/C:/w/incubator-ignite/modules/core/target/classes/) to field java.nio.Buffer.address", |
| "WARNING: Please consider reporting this to the maintainers of org.apache.ignite.internal.util." + |
| "GridUnsafe$2", |
| "WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations", |
| "WARNING: All illegal access operations will be denied in a future release" |
| }; |
| |
| Action<string, string> checkError = (args, err) => |
| { |
| var reader = new ListDataReader(); |
| var proc = new IgniteProcess(reader, args); |
| |
| int exitCode; |
| Assert.IsTrue(proc.Join(30000, out exitCode)); |
| Assert.AreEqual(-1, exitCode); |
| |
| Assert.AreEqual(err, reader.GetOutput() |
| .Except(ignoredWarns) |
| .FirstOrDefault(x => !string.IsNullOrWhiteSpace(x))); |
| }; |
| |
| checkError("blabla", "ERROR: Apache.Ignite.Core.Common.IgniteException: Missing argument value: " + |
| "'blabla'. See 'Apache.Ignite.exe /help'"); |
| |
| checkError("blabla=foo", "ERROR: Apache.Ignite.Core.Common.IgniteException: " + |
| "Unknown argument: 'blabla'. See 'Apache.Ignite.exe /help'"); |
| |
| checkError("assembly=", "ERROR: Apache.Ignite.Core.Common.IgniteException: Missing argument value: " + |
| "'assembly'. See 'Apache.Ignite.exe /help'"); |
| |
| checkError("assembly=x.dll", "ERROR: Apache.Ignite.Core.Common.IgniteException: " + |
| "Failed to load assembly: x.dll"); |
| |
| checkError("configFileName=wrong.config", "ERROR: System.Configuration.ConfigurationErrorsException: " + |
| "Specified config file does not exist: wrong.config"); |
| |
| checkError("configSectionName=wrongSection", "ERROR: System.Configuration.ConfigurationErrorsException: " + |
| "Could not find IgniteConfigurationSection " + |
| "in current application configuration"); |
| |
| checkError("JvmInitialMemoryMB=A_LOT", "ERROR: System.InvalidOperationException: Failed to configure " + |
| "Ignite: property 'JvmInitialMemoryMB' has value 'A_LOT', " + |
| "which is not an integer."); |
| |
| checkError("JvmMaxMemoryMB=ALL_OF_IT", "ERROR: System.InvalidOperationException: Failed to configure " + |
| "Ignite: property 'JvmMaxMemoryMB' has value 'ALL_OF_IT', " + |
| "which is not an integer."); |
| } |
| |
| /// <summary> |
| /// Tests a scenario where XML config has references to types from dynamically loaded assemblies. |
| /// </summary> |
| [Test] |
| public void TestXmlConfigurationReferencesTypesFromDynamicallyLoadedAssemblies() |
| { |
| const string code = @" |
| using System; |
| using Apache.Ignite.Core.Log; |
| namespace CustomNs { |
| class CustomLogger : ILogger { |
| public void Log(LogLevel level, string message, object[] args, IFormatProvider formatProvider, |
| string category, string nativeErrorInfo, Exception ex) {} |
| public bool IsEnabled(LogLevel level) { return true; } |
| } }"; |
| |
| var dllPath = GenerateDll("CustomAsm.dll", true, code); |
| |
| var proc = new IgniteProcess( |
| "-configFileName=config\\ignite-dotnet-cfg-logger.xml", |
| "-assembly=" + dllPath); |
| |
| Assert.IsTrue(proc.Alive); |
| Assert.IsTrue(_grid.WaitTopology(2)); |
| |
| var remoteCfg = RemoteConfig(); |
| Assert.AreEqual("CustomNs.CustomLogger", remoteCfg.LoggerTypeName); |
| } |
| |
| /// <summary> |
| /// Get remote node configuration. |
| /// </summary> |
| /// <returns>Configuration.</returns> |
| private RemoteConfiguration RemoteConfig() |
| { |
| return _grid.GetCluster().ForRemotes().GetCompute().Call(new RemoteConfigurationClosure()); |
| } |
| |
| /// <summary> |
| /// Generates a DLL dynamically. |
| /// </summary> |
| /// <param name="outputPath">Target path.</param> |
| /// <param name="randomPath">Whether to use random path.</param> |
| /// <param name="code">Code to compile.</param> |
| private string GenerateDll(string outputPath, bool randomPath = false, string code = null) |
| { |
| // Put resulting DLLs to the random temp dir to make sure they are not resolved from current dir. |
| var resPath = randomPath ? Path.Combine(_tempDir, outputPath) : outputPath; |
| |
| var parameters = new CompilerParameters |
| { |
| GenerateExecutable = false, |
| OutputAssembly = resPath, |
| ReferencedAssemblies = { typeof(IIgnite).Assembly.Location } |
| }; |
| |
| var src = code ?? "namespace Apache.Ignite.Client.Test { public class Foo {}}"; |
| |
| var results = CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromSource(parameters, src); |
| |
| Assert.False( |
| results.Errors.HasErrors, |
| string.Join(Environment.NewLine, results.Errors.Cast<CompilerError>().Select(e => e.ToString()))); |
| |
| return resPath; |
| } |
| |
| /// <summary> |
| /// Asserts that JVM maximum memory corresponds to Xmx parameter value. |
| /// </summary> |
| private static void AssertJvmMaxMemory(long expected, long actual) |
| { |
| // allow 20% tolerance because max memory in Java is not exactly equal to Xmx parameter value |
| Assert.LessOrEqual(actual, expected / 4 * 5); |
| Assert.Greater(actual, expected / 5 * 4); |
| } |
| |
| /// <summary> |
| /// Closure which extracts configuration and passes it back. |
| /// </summary> |
| private class RemoteConfigurationClosure : IComputeFunc<RemoteConfiguration> |
| { |
| |
| #pragma warning disable 0649 |
| |
| /** Grid. */ |
| [InstanceResource] private IIgnite _grid; |
| |
| #pragma warning restore 0649 |
| |
| /** <inheritDoc /> */ |
| |
| public RemoteConfiguration Invoke() |
| { |
| var grid0 = (Ignite) _grid; |
| |
| var cfg = grid0.Configuration; |
| |
| var res = new RemoteConfiguration |
| { |
| IgniteHome = cfg.IgniteHome, |
| SpringConfigUrl = cfg.SpringConfigUrl, |
| JvmDll = cfg.JvmDllPath, |
| JvmClasspath = cfg.JvmClasspath, |
| JvmOptions = cfg.JvmOptions, |
| Assemblies = cfg.Assemblies, |
| LoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToArray(), |
| JvmInitialMemoryMb = cfg.JvmInitialMemoryMb, |
| JvmMaxMemoryMb = cfg.JvmMaxMemoryMb, |
| LoggerTypeName = cfg.Logger == null ? null : cfg.Logger.GetType().FullName |
| }; |
| |
| Console.WriteLine("RETURNING CFG: " + cfg); |
| |
| return res; |
| } |
| } |
| |
| /// <summary> |
| /// Configuration. |
| /// </summary> |
| private class RemoteConfiguration |
| { |
| /// <summary> |
| /// GG home. |
| /// </summary> |
| public string IgniteHome { get; set; } |
| |
| /// <summary> |
| /// Spring config URL. |
| /// </summary> |
| public string SpringConfigUrl { get; set; } |
| |
| /// <summary> |
| /// JVM DLL. |
| /// </summary> |
| public string JvmDll { get; set; } |
| |
| /// <summary> |
| /// JVM classpath. |
| /// </summary> |
| public string JvmClasspath { get; set; } |
| |
| /// <summary> |
| /// JVM options. |
| /// </summary> |
| public ICollection<string> JvmOptions { get; set; } |
| |
| /// <summary> |
| /// Assemblies. |
| /// </summary> |
| public ICollection<string> Assemblies { get; set; } |
| |
| /// <summary> |
| /// Assemblies. |
| /// </summary> |
| public ICollection<string> LoadedAssemblies { get; set; } |
| |
| /// <summary> |
| /// Minimum JVM memory (Xms). |
| /// </summary> |
| public int JvmInitialMemoryMb { get; set; } |
| |
| /// <summary> |
| /// Maximum JVM memory (Xms). |
| /// </summary> |
| public int JvmMaxMemoryMb { get; set; } |
| |
| /// <summary> |
| /// Logger type name. |
| /// </summary> |
| public string LoggerTypeName { get; set; } |
| } |
| } |
| } |
| #endif |