/// <summary>
        /// Creates a new test run and places it into pending status.
        /// </summary>
        /// <param name="workingDirectory">The current working directory for the build agent.</param>
        /// <returns>The identifier of the test run within the database.</returns>
        public Int64 CreateTestRun(String workingDirectory)
        {
            using (var testRunContext = new TestRunContext())
            {
                var run = new TestRun() { Status = TestRunStatus.Pending, WorkingDirectory = workingDirectory };

                testRunContext.TestRuns.Add(run);
                testRunContext.SaveChanges();

                return run.ID;
            }
        }
        /// <summary>
        /// Executes the specified test run.
        /// </summary>
        /// <param name="testRun">The test run to execute.</param>
        /// <returns>The identifier of the test run within the database.</returns>
        public Int64 Run(TestRun testRun)
        {
            if (testRun == null)
                throw new ArgumentNullException("testRun");

            var id = testRun.ID;
            var workingDirectory = testRun.WorkingDirectory;

            // Start by spawning the test runner process and running the unit test suite.
            UpdateTestRunStatus(id, TestRunStatus.Running);
            var psi = new ProcessStartInfo(Settings.Default.TestHostExecutable, Settings.Default.TestHostArgs)
            {
                WorkingDirectory = Path.Combine(Settings.Default.TestRootDirectory, workingDirectory).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
            };
            var proc = Process.Start(psi);
            proc.WaitForExit();

            // If the test runner exited with an error, log it to the database and bail out.
            var testFramework = (Settings.Default.TestFramework ?? "mstest").ToLowerInvariant();
            var testFrameworkFailed = (testFramework == "mstest") ?
                (proc.ExitCode != 0 && proc.ExitCode != 1) :
                (proc.ExitCode < 0);

            if (testFrameworkFailed)
            {
                UpdateTestRunStatus(id, TestRunStatus.Failed);
                return id;
            }

            // Determine the location of the test result file...
            var testResultsRoot = Path.Combine(Settings.Default.TestRootDirectory, workingDirectory, Settings.Default.TestOutputDirectory);
            var testResultPath = String.Empty;
            var testResultImagesPath = String.Empty;

            /* If the tests ran successfully, find the folder that contains the test results.
             * TODO: The way we do this currently introduces a race condition if the test suite is being run simultaneously
             * in multiple threads, which shouldn't realistically happen, but this case probably
             * ought to be handled anyway for robustness. */
            DirectoryInfo relevantTestResult;
            try
            {
                if (testFramework == "mstest")
                {
                    var testResultsDirs = Directory.GetDirectories(testResultsRoot)
                        .Where(x => x.Contains("_" + Environment.MachineName.ToUpper() + " "))
                        .Select(x => new DirectoryInfo(x));

                    relevantTestResult = testResultsDirs.OrderByDescending(x => x.CreationTimeUtc).FirstOrDefault();

                    if (relevantTestResult == null)
                    {
                        UpdateTestRunStatus(id, TestRunStatus.Failed);
                        return id;
                    }

                    testResultPath = Path.ChangeExtension(Path.Combine(relevantTestResult.Parent.FullName, relevantTestResult.Name), "trx");
                    testResultImagesPath = Path.Combine(relevantTestResult.FullName, "Out");
                }
                else
                {
                    relevantTestResult = new DirectoryInfo(testResultsRoot);

                    testResultPath = Path.Combine(testResultsRoot, Settings.Default.TestResultFile);
                    testResultImagesPath = Path.Combine(testResultsRoot, GetSanitizedMachineName());
                }
            }
            catch (DirectoryNotFoundException)
            {
                UpdateTestRunStatus(id, TestRunStatus.Failed);
                return id;
            }

            // Optionally rewrite test names.
            if (!String.IsNullOrEmpty(Settings.Default.TestNameRewriteRule))
            {
                switch (testFramework)
                {
                    case "mstest":
                        RewriteTestNames_MSTest(testResultPath);
                        break;

                    case "nunit3":
                        RewriteTestNames_NUnit3(testResultPath);
                        break;
                }
            }

            // Create a directory to hold this test's artifacts.
            var outputDirectory = Path.Combine(Settings.Default.TestResultDirectory, workingDirectory, id.ToString());
            Directory.CreateDirectory(outputDirectory);

            // Copy the result file and any outputted PNG files to the artifact directory.
            var resultFileSrc = testResultPath;
            var resultFileDst = Path.Combine(outputDirectory, Settings.Default.TestResultFile);
            CopyFile(resultFileSrc, resultFileDst);

            var pngFiles = Directory.GetFiles(testResultImagesPath, "*.png");
            foreach (var pngFile in pngFiles)
            {
                var pngFileSrc = pngFile;
                var pngFileDst = Path.Combine(outputDirectory, Path.GetFileName(pngFileSrc));
                CopyFile(pngFileSrc, pngFileDst);
            }

            var resultStatus = GetStatusFromTestResult(resultFileSrc);
            UpdateTestRunStatus(id, resultStatus);

            return id;
        }