blob: c882e1dd18ffccbb66d92d07ad225f1441d9896e [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
{
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Communication.Tcp;
using Apache.Ignite.Core.Tests.Binary;
using NUnit.Framework;
/// <summary>
/// Tests that Java console output is redirected to .NET console.
/// </summary>
public class ConsoleRedirectTest
{
/** Thread name task name. */
private const string ConsoleWriteTask = "org.apache.ignite.platform.PlatformConsoleWriteTask";
/** */
private StringBuilder _outSb;
/** */
private StringBuilder _errSb;
/** */
private TextWriter _stdOut;
/** */
private TextWriter _stdErr;
/// <summary>
/// Sets up the test.
/// </summary>
[SetUp]
public void SetUp()
{
_stdOut = Console.Out;
_stdErr = Console.Error;
_outSb = new StringBuilder();
Console.SetOut(new MyStringWriter(_outSb));
_errSb = new StringBuilder();
Console.SetError(new MyStringWriter(_errSb));
}
/// <summary>
/// Tears down the test.
/// </summary>
[TearDown]
public void TearDown()
{
MyStringWriter.Throw = false;
Console.SetOut(_stdOut);
Console.SetError(_stdErr);
Ignition.StopAll(true);
}
/// <summary>
/// Tests the startup output.
/// </summary>
[Test]
public void TestStartupOutput()
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
Logger = null
};
using (Ignition.Start(cfg))
{
Assert.AreEqual(1, Regex.Matches(_outSb.ToString(), "ver=1, locNode=[a-fA-F0-9]{8,8}, servers=1, clients=0,").Count);
}
}
/// <summary>
/// Tests the exception in console writer.
/// </summary>
[Test]
public void TestExceptionInWriterPropagatesToJavaAndBack()
{
MyStringWriter.Throw = true;
var ex = Assert.Throws<IgniteException>(() => Ignition.Start(TestUtils.GetTestConfiguration()));
Assert.AreEqual("foo", ex.Message);
}
[Test]
public void TestConsoleWriteSpecialStrings()
{
var ignite = Ignition.Start(TestUtils.GetTestConfiguration());
foreach (var val in BinarySelfTest.SpecialStrings)
{
MyStringWriter.LastValue = null;
// Send to Java as UTF-16 to avoid dealing with IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2
var bytes = Encoding.Unicode.GetBytes(MyStringWriter.Prefix + val);
ignite.GetCompute().ExecuteJavaTask<string>(ConsoleWriteTask, bytes);
var expectedStr = GetExpectedStr(val);
Assert.AreEqual(expectedStr, MyStringWriter.LastValue, message: val);
StringAssert.Contains(expectedStr, _outSb.ToString(), message: val);
// Test Env.NewString
MyStringWriter.LastValue = null;
TestUtilsJni.Println(MyStringWriter.Prefix + val);
Assert.AreEqual(expectedStr.Length, MyStringWriter.LastValue?.Length, message: val);
if (val != BinarySelfTest.SpecialStrings[0])
{
Assert.AreEqual(expectedStr, MyStringWriter.LastValue, message: val);
}
}
}
/// <summary>
/// Tests startup error in Java.
/// </summary>
[Test]
public void TestStartupJavaError()
{
// Invalid config
Assert.Throws<IgniteException>(() =>
Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
CommunicationSpi = new TcpCommunicationSpi
{
IdleConnectionTimeout = TimeSpan.MinValue
},
Logger = null
}));
StringAssert.Contains("SPI parameter failed condition check: idleConnTimeout > 0", _errSb.ToString());
}
#if !NETCOREAPP
/// <summary>
/// Tests the disabled redirect.
/// </summary>
[Test]
public void TestDisabledRedirect()
{
// Run test in new process because JVM is initialized only once.
const string envVar = "ConsoleRedirectTest.TestDisabledRedirect";
if (Environment.GetEnvironmentVariable(envVar) == bool.TrueString)
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration(false))
{
Logger = null
};
Assert.IsTrue(cfg.RedirectJavaConsoleOutput);
cfg.RedirectJavaConsoleOutput = false;
using (Ignition.Start(cfg))
{
Assert.AreEqual(string.Empty, _errSb.ToString());
Assert.AreEqual(string.Empty, _outSb.ToString());
}
}
else
{
using (EnvVar.Set(envVar, bool.TrueString))
{
TestUtils.RunTestInNewProcess(GetType().FullName, "TestDisabledRedirect");
}
}
}
/// <summary>
/// Tests multiple appdomains and multiple console handlers.
/// </summary>
[Test]
public void TestMultipleDomains()
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration(noLogger: true));
using (var ignite = Ignition.Start(cfg))
{
Assert.AreEqual(1, Regex.Matches(_outSb.ToString(), "ver=1, locNode=[a-fA-F0-9]{8,8}, servers=1, clients=0,").Count);
// Run twice
RunInNewDomain();
RunInNewDomain();
Assert.AreEqual(5, ignite.GetCluster().TopologyVersion);
var outTxt = _outSb.ToString();
// Check output from another domain (2 started + 2 stopped = 4)
Assert.AreEqual(4, Regex.Matches(outTxt, ">>> Ignite instance name: newDomainGrid").Count);
// Both domains produce the topology snapshot on node enter
Assert.AreEqual(2, Regex.Matches(outTxt, "ver=2, locNode=[a-fA-F0-9]{8,8}, servers=2, clients=0,").Count);
Assert.AreEqual(1, Regex.Matches(outTxt, "ver=3, locNode=[a-fA-F0-9]{8,8}, servers=1, clients=0,").Count);
Assert.AreEqual(2, Regex.Matches(outTxt, "ver=4, locNode=[a-fA-F0-9]{8,8}, servers=2, clients=0,").Count);
Assert.AreEqual(1, Regex.Matches(outTxt, "ver=5, locNode=[a-fA-F0-9]{8,8}, servers=1, clients=0,").Count);
}
}
/// <summary>
/// Runs the Ignite in a new domain.
/// </summary>
private static void RunInNewDomain()
{
AppDomain childDomain = null;
try
{
childDomain = AppDomain.CreateDomain("Child", null, new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
LoaderOptimization = LoaderOptimization.MultiDomainHost
});
var type = typeof(IgniteRunner);
Assert.IsNotNull(type.FullName);
var runner = (IIgniteRunner)childDomain.CreateInstanceAndUnwrap(
type.Assembly.FullName, type.FullName);
runner.Run();
}
finally
{
if (childDomain != null)
AppDomain.Unload(childDomain);
}
}
private interface IIgniteRunner
{
void Run();
}
private class IgniteRunner : MarshalByRefObject, IIgniteRunner
{
public void Run()
{
Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration(noLogger: true))
{
IgniteInstanceName = "newDomainGrid"
});
// Will be stopped automatically on domain unload.
}
}
#endif
private static string GetExpectedStr(string val)
{
if (val != BinarySelfTest.SpecialStrings[0])
{
return val;
}
// Some special strings are not equal to themselves after UTF16 roundtrip,
// even though they contain exactly the same bytes.
return Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(val));
}
private class MyStringWriter : StringWriter
{
public const string Prefix = "[MyStringWriter]";
public static bool Throw { get; set; }
public static string LastValue { get; set; }
public MyStringWriter(StringBuilder sb) : base(sb)
{
// No-op.
}
public override void Write(string value)
{
if (Throw)
{
throw new Exception("foo");
}
base.Write(value);
if (!string.IsNullOrWhiteSpace(value) && value.StartsWith(Prefix))
{
LastValue = value.Substring(Prefix.Length);
}
}
}
}
}