[JENKINS-42744] - Reproduce the issue in the unit test

pull/202/head
Oleg Nenashev 2017-03-31 13:02:53 +02:00
parent 615519f6a3
commit 9fc518a3d0
4 changed files with 110 additions and 16 deletions

View File

@ -118,7 +118,6 @@ namespace winsw.Util
}
}
//TODO: generalize API
/// <summary>
/// Starts a process and asynchronosly waits for its termination.
/// Once the process exits, the callback will be invoked.
@ -129,24 +128,27 @@ namespace winsw.Util
/// <param name="envVars">Additional environment variables</param>
/// <param name="workingDirectory">Working directory</param>
/// <param name="priority">Priority</param>
/// <param name="callback">Completion callback</param>
public static void StartProcessAndCallbackForExit(Process processToStart, String executable, string arguments, Dictionary<string, string> envVars,
string workingDirectory, ProcessPriorityClass priority, ProcessCompletionCallback callback)
/// <param name="callback">Completion callback. If null, the completion won't be monitored</param>
public static void StartProcessAndCallbackForExit(Process processToStart, String executable = null, string arguments = null, Dictionary<string, string> envVars = null,
string workingDirectory = null, ProcessPriorityClass? priority = null, ProcessCompletionCallback callback = null)
{
var ps = processToStart.StartInfo;
ps.FileName = executable;
ps.Arguments = arguments;
ps.WorkingDirectory = workingDirectory;
ps.FileName = executable ?? ps.FileName;
ps.Arguments = arguments ?? ps.Arguments;
ps.WorkingDirectory = workingDirectory ?? ps.WorkingDirectory;
ps.CreateNoWindow = false;
ps.UseShellExecute = false;
ps.RedirectStandardInput = true; // this creates a pipe for stdin to the new process, instead of having it inherit our stdin.
ps.RedirectStandardOutput = true;
ps.RedirectStandardError = true;
foreach (string key in envVars.Keys)
if (envVars != null)
{
Environment.SetEnvironmentVariable(key, envVars[key]);
// ps.EnvironmentVariables[key] = envs[key]; // bugged (lower cases all variable names due to StringDictionary being used, see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=326163)
foreach (string key in envVars.Keys)
{
Environment.SetEnvironmentVariable(key, envVars[key]);
// ps.EnvironmentVariables[key] = envs[key]; // bugged (lower cases all variable names due to StringDictionary being used, see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=326163)
}
}
//TODO: move outside, stubbed to reproduce the issue
@ -157,15 +159,20 @@ namespace winsw.Util
processToStart.Start();
Logger.Info("Started process " + processToStart.Id);
if (priority != ProcessPriorityClass.Normal)
processToStart.PriorityClass = priority;
if (priority != null && priority.Value != ProcessPriorityClass.Normal)
{
processToStart.PriorityClass = priority.Value;
}
// monitor the completion of the process
StartThread(delegate
if (callback != null)
{
processToStart.WaitForExit();
callback(processToStart);
});
StartThread(delegate
{
processToStart.WaitForExit();
callback(processToStart);
});
}
}
/// <summary>

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace winswTests.Util
{
class FilesystemTestHelper
{
/// <summary>
/// Creates a temporary directory for testing.
/// </summary>
/// <returns>tmp Dir</returns>
public static string CreateTmpDirectory(String testName = null)
{
string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? "") + Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
Console.Out.WriteLine("Created the temporary directory: {0}", tempDirectory);
return tempDirectory;
}
/// <summary>
/// Parses output of the "set" command from the file
/// </summary>
/// <param name="filePath">File path</param>
/// <returns>Dictionary of the strings.</returns>
public static Dictionary<string, string> parseSetOutput(string filePath)
{
Dictionary<string, string> res = new Dictionary<string, string>();
var lines = File.ReadAllLines(filePath);
foreach(var line in lines) {
line.Split("=".ToCharArray(), 2);
}
return res;
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Diagnostics;
using NUnit.Framework;
using winsw;
using System.IO;
using winsw.Util;
namespace winswTests.Util
{
[TestFixture]
class ProcessHelperTest
{
/// <summary>
/// Also reported as <a href="https://issues.jenkins-ci.org/browse/JENKINS-42744">JENKINS-42744</a>
/// </summary>
[Test]
public void ShouldPropagateVariablesInUppercase()
{
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
String envFile = Path.Combine(tmpDir, "env.properties");
String scriptFile = Path.Combine(tmpDir, "printenv.bat");
File.WriteAllText(scriptFile, "set > " + envFile);
Process proc = new Process();
var ps = proc.StartInfo;
ps.FileName = scriptFile;
ProcessHelper.StartProcessAndCallbackForExit(proc);
var exited = proc.WaitForExit(5000);
if (!exited)
{
Assert.Fail("Process " + proc + " didn't exit after 5 seconds");
}
// Check several veriables, which are expected to be in Uppercase
var envVars = FilesystemTestHelper.parseSetOutput(envFile);
Assert.That(envVars.ContainsKey("PROCESSOR_ARCHITECTURE"), "No PROCESSOR_ARCHITECTURE in the injected vars");
Assert.That(envVars.ContainsKey("COMPUTERNAME"), "No COMPUTERNAME in the injected vars");
Assert.That(envVars.ContainsKey("PATHEXT"), "No PATHEXT in the injected vars");
// And just ensure that the parsing logic is case-sensitive
Assert.That(!envVars.ContainsKey("computername"), "Test error: the environment parsing logic is case-insensitive");
}
}
}

View File

@ -60,6 +60,8 @@
<Compile Include="Extensions\RunawayProcessKillerTest.cs" />
<Compile Include="Extensions\SharedDirectoryMapperTest.cs" />
<Compile Include="MainTest.cs" />
<Compile Include="Util\FilesystemTestHelper.cs" />
<Compile Include="Util\ProcessHelperTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceDescriptorTests.cs" />
<Compile Include="Util\CLITestHelper.cs" />