/// <summary>
        /// Initializes a new instance of the <see cref="TestStepParameterController"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="diagnostics">The object that provides the diagnostics methods for the application.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="context"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="diagnostics"/> is <see langword="null" />.
        /// </exception>
        public TestStepParameterController(IProvideTestingContext context, SystemDiagnostics diagnostics)
        {
            {
                Lokad.Enforce.Argument(() => context);
                Lokad.Enforce.Argument(() => diagnostics);
            }

            m_Context = context;
            m_Diagnostics = diagnostics;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TestStepAdditionalReportFilesController"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="diagnostics">The object that provides the diagnostics methods for the application.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="context"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="diagnostics"/> is <see langword="null" />.
        /// </exception>
        public TestStepAdditionalReportFilesController(IProvideTestingContext context, SystemDiagnostics diagnostics)
        {
            {
                Lokad.Enforce.Argument(() => context);
                Lokad.Enforce.Argument(() => diagnostics);
            }

            m_Context = context;
            m_Diagnostics = diagnostics;
        }
        private void LoadEnvironmentsAndStartTest(
            IProvideTestingContext currentContext,
            Test test,
            List<Tuple<MachineDescription, TestEnvironment>> matchingEnvironments,
            IReportBuilder builder)
        {
            var initializeSection = m_SectionBuilders(Resources.ReportSection_Group_Name_Initialization, builder);
            initializeSection.Initialize(Resources.ReportSection_Name_LoadEnvironments);
            var parameters = matchingEnvironments.Select(t => new InputParameter(t.Item2.Name, t.Item1.NetworkName));
            var testFile = TestHelpers.StoragePathForTestFiles(test.Id, m_Configuration, m_FileSystem);
            try
            {
                try
                {
                    foreach (var pair in matchingEnvironments)
                    {
                        m_Diagnostics.Log(
                            LevelToLog.Debug,
                            MasterServiceConstants.LogPrefix,
                            string.Format(
                                CultureInfo.InvariantCulture,
                                Resources.Log_Messages_ActivatingEnvironment_WithTestAndEnvironment,
                                test.Id,
                                pair.Item2.Name));

                        var environmentSection = m_SectionBuilders(Resources.ReportSection_Group_Name_Environments, builder);
                        environmentSection.Initialize(pair.Item2.Name);
                        var environment = ActivateMachineForEnvironment(currentContext, pair.Item1, pair.Item2, environmentSection);
                        m_ExecutingTests.AddEnvironmentForTest(test.Id, environment);

                        var testSteps = new List<TestStep>();
                        foreach (var step in currentContext.TestStepsForEnvironment(pair.Item2.Id).OrderBy(s => s.Order))
                        {
                            // Copy the test steps and strip all links that are not remotely related to any of the work
                            // we're about to do.
                            var copy = CopyStepAndStripNonEssentialInformation(step);
                            testSteps.Add(copy);
                        }

                        m_Diagnostics.Log(
                            LevelToLog.Debug,
                            MasterServiceConstants.LogPrefix,
                            string.Format(
                                CultureInfo.InvariantCulture,
                                Resources.Log_Messages_PackagingTestFilesForEnvironment_WithTestAndEnvironment,
                                test.Id,
                                pair.Item2));

                        var suite = m_TestSuitePackageFactory();
                        suite.LoadAndUnpack(
                            testFile,
                            Path.Combine(m_UnpackDirectory, test.Id.ToString(CultureInfo.InvariantCulture), pair.Item2.Name));
                        var environmentFile = suite.Environment(pair.Item2.Name);

                        m_Diagnostics.Log(
                            LevelToLog.Debug,
                            MasterServiceConstants.LogPrefix,
                            string.Format(
                                CultureInfo.InvariantCulture,
                                Resources.Log_Messages_ExecutingTestOnEnvironment_WithTestAndEnvironment,
                                test.Id,
                                pair.Item2));
                        environment.Execute(test.Id, testSteps, parameters, environmentFile.PackagePath);
                    }

                    // Start the test
                    currentContext.StartTest(test.Id);
                }
                finally
                {
                    var logText = string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.Log_Messages_StartedTestOnEnvironments,
                        test.Id,
                        string.Join(", ", matchingEnvironments.Select(t => new Tuple<string, string>(t.Item1.Id, t.Item2.Name))));
                    m_Diagnostics.Log(LevelToLog.Info, MasterServiceConstants.LogPrefix, logText);
                }
            }
            catch (Exception e)
            {
                // complete the test
                var activeEnvironments = m_ExecutingTests.EnvironmentsForTest(test.Id).ToList();
                foreach (var environment in activeEnvironments)
                {
                    try
                    {
                        environment.Shutdown();
                    }
                    catch (Exception ex)
                    {
                        m_Diagnostics.Log(
                            LevelToLog.Error,
                            MasterServiceConstants.LogPrefix,
                            string.Format(
                                CultureInfo.InvariantCulture,
                                Resources.Log_Messages_FailedToShutdownEnvironment_WithError,
                                ex));
                    }
                }

                m_ExecutingTests.Remove(test.Id);
                if (test.StartTime.HasValue && !test.EndTime.HasValue)
                {
                    currentContext.StopTest(test.Id);
                }

                // In all cases do we remove the test. If it falls over then a report will be produced showing
                // why it didn't work
                m_Diagnostics.Log(
                    LevelToLog.Error,
                    MasterServiceConstants.LogPrefix,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.Log_Messages_FailedToStartEnvironments_WithError,
                        e));
                initializeSection.AddErrorMessage(Resources.ReportSection_Error_FailedToStartEnvironments);
                initializeSection.FinalizeAndStore(false);
            }
        }
        /// <summary>
        /// Activates the given machine and returns an object that can be used to manipulate
        /// the machine.
        /// </summary>
        /// <param name="currentContext">The current data storage context.</param>
        /// <param name="machine">The description of the machine.</param>
        /// <param name="environment">The description of the environment.</param>
        /// <param name="sectionBuilder">
        ///     The object used to write information to the report about the starting and stopping of the machine.
        /// </param>
        /// <returns>An object that is used to manipulate the active machine.</returns>
        private IActiveEnvironment ActivateMachineForEnvironment(
            IProvideTestingContext currentContext,
            MachineDescription machine,
            TestEnvironment environment,
            ITestSectionBuilder sectionBuilder)
        {
            lock (m_Lock)
            {
                {
                    Lokad.Enforce.Argument(() => machine);
                    Lokad.Enforce.With<ArgumentException>(
                        m_Activators.Any(a => a.EnvironmentTypeToLoad == machine.GetType()),
                        Resources.Exceptions_Messages_NoActivatorHasBeenRegisteredForTheEnvironment);
                }

                var activator = m_Activators.Find(a => a.EnvironmentTypeToLoad == machine.GetType());
                Debug.Assert(activator != null, "We should have found an activator.");

                var activeEnvironment = activator.Load(machine, sectionBuilder, OnEnvironmentUnloaded);

                currentContext.MarkMachineAsActive(machine.Id);
                currentContext.TestEnvironmentSupportedByMachine(environment.Id, machine.Id);

                return activeEnvironment;
            }
        }