public void TestPullTester()
{
var javaTimeout = (int)TimeSpan.FromMinutes(2).TotalMilliseconds;
// locate java.exe
var javaPath = Path.Combine(Environment.GetEnvironmentVariable("JAVA_HOME"), "bin", "java.exe");
if (!File.Exists(javaPath))
Assert.Inconclusive("java.exe could not be found under JAVA_HOME");
// prepare a temp folder for bitcoinj
string tempFolder;
using (TempDirectory.CreateTempDirectory(out tempFolder))
// initialize kernel
using (var kernel = new StandardKernel())
{
var tempFile = Path.Combine(tempFolder, "BitcoindComparisonTool");
var jarFile = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "pull-tests.jar");
// add logging module
kernel.Load(new ConsoleLoggingModule(LogLevel.Info));
// log startup
var logger = LogManager.GetCurrentClassLogger();
logger.Info($"Starting up: {DateTime.Now}");
// add rules module
var chainType = ChainType.Regtest;
kernel.Load(new RulesModule(chainType));
// add storage module
kernel.Load(new MemoryStorageModule());
kernel.Load(new NetworkMemoryStorageModule());
// initialize the blockchain daemon
using (var coreDaemon = kernel.Get<CoreDaemon>())
{
kernel.Bind<CoreDaemon>().ToConstant(coreDaemon).InTransientScope();
// initialize p2p client
using (var localClient = kernel.Get<LocalClient>())
{
kernel.Bind<LocalClient>().ToConstant(localClient).InTransientScope();
// start the blockchain daemon
coreDaemon.Start();
// find a free port
var port = FindFreePort();
Messaging.Port = port;
// start p2p client
localClient.Start();
// run pull tester
var runLargeReorgs = 0;
var javaProcessInfo = new ProcessStartInfo
{
FileName = javaPath,
Arguments = $"-jar \"{jarFile}\" \"{tempFile}\" {runLargeReorgs} {port}",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using (var javaProcess = Process.Start(javaProcessInfo))
{
try
{
var errorOccurred = false;
var output = new StringBuilder();
var successOutput = new StringBuilder();
var errorOutput = new StringBuilder();
var onOutput = new DataReceivedEventHandler(
(sender, e) =>
{
if (e.Data?.Contains("ERROR:") ?? false)
errorOccurred = true;
output.AppendLine(e.Data);
if (!errorOccurred)
successOutput.AppendLine(e.Data);
else
errorOutput.AppendLine(e.Data);
});
javaProcess.OutputDataReceived += onOutput;
javaProcess.ErrorDataReceived += onOutput;
javaProcess.BeginOutputReadLine();
javaProcess.BeginErrorReadLine();
var didJavaExit = javaProcess.WaitForExit(javaTimeout);
javaProcess.OutputDataReceived -= onOutput;
javaProcess.ErrorDataReceived -= onOutput;
logger.Info($"Pull Tester Result: {(didJavaExit ? (int?)javaProcess.ExitCode : null)}");
// verify pull tester successfully connected
Assert.IsTrue(output.ToString().Contains(
$"NioClientManager.handleKey: Successfully connected to /127.0.0.1:{port}"),
$"Failed to connect: {output}");
if (errorOccurred || !didJavaExit || javaProcess.ExitCode != 0)
{
// log all success & error output from the comparison tool
string line;
using (var reader = new StringReader(successOutput.ToString()))
while ((line = reader.ReadLine()) != null)
logger.Info(line);
using (var reader = new StringReader(errorOutput.ToString()))
while ((line = reader.ReadLine()) != null)
logger.Error(line);
// don't fail on pull tester result, consensus is not implemented and it will always fail
if (didJavaExit)
Assert.Inconclusive(errorOutput.Length > 0 ? errorOutput.ToString() : output.ToString());
else
{
// if java.exe failed to terminate, log last X lines of output
var lastLinesCount = 20;
var lastLines = new List<string>(lastLinesCount);
var match = Regex.Match(output.ToString(), "^.*$", RegexOptions.Multiline | RegexOptions.RightToLeft);
var count = 0;
while (count < lastLinesCount && (match = match.NextMatch()) != null)
{
lastLines.Add(match.Value);
count++;
}
lastLines.Reverse();
Assert.Fail($"java.exe failed to terminate: {string.Join("", lastLines)}");
}
}
Assert.AreEqual(0, javaProcess.ExitCode);
}
finally
{
// ensure java.exe is terminated
try { javaProcess.Kill(); }
catch (InvalidOperationException) { }
}
}
}
}
}
}