/// <summary>
        /// Initializes a new instance of the <see cref="XCopyDeployTestStepProcessor"/> class.
        /// </summary>
        /// <param name="testFileLocation">
        /// The function that takes the name of the test step and returns the full path to the directory containing the files for the 
        /// given test step.
        /// </param>
        /// <param name="reportFileUploader">
        /// The function that is used to upload the report files for the current test step.
        /// </param>
        /// <param name="diagnostics">The object that provides the diagnostics methods for the application.</param>
        /// <param name="fileSystem">The object that provides access to the file system.</param>
        /// <param name="sectionBuilder">The section builder.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="testFileLocation"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="reportFileUploader"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="diagnostics"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="fileSystem"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="sectionBuilder"/> is <see langword="null" />.
        /// </exception>
        public XCopyDeployTestStepProcessor(
            RetrieveFileDataForTestStep testFileLocation,
            UploadReportFilesForTestStep reportFileUploader,
            SystemDiagnostics diagnostics,
            IFileSystem fileSystem,
            ITestSectionBuilder sectionBuilder)
            : base(testFileLocation, reportFileUploader, diagnostics)
        {
            {
                Lokad.Enforce.Argument(() => fileSystem);
                Lokad.Enforce.Argument(() => sectionBuilder);
            }

            m_FileSystem = fileSystem;
            m_SectionBuilder = sectionBuilder;
        }
Esempio n. 2
0
        /// <summary>
        /// Transfers the report files back to the host.
        /// </summary>
        /// <param name="sectionBuilder">The object that stores the report messages.</param>
        /// <param name="testStep">The test step for which the files should be uploaded.</param>
        /// <param name="additionalFilesToInclude">A collection containing the additional files that should be included in the report.</param>
        protected void TransferReportFiles(
            ITestSectionBuilder sectionBuilder,
            TestStep testStep,
            IEnumerable<string> additionalFilesToInclude = null)
        {
            try
            {
                var filesToTransfer = new Dictionary<FileInfo, DirectoryInfo>();
                foreach (var file in testStep.ReportFiles)
                {
                    if (File.Exists(file.Path))
                    {
                        filesToTransfer.Add(new FileInfo(file.Path), new DirectoryInfo(Path.GetDirectoryName(file.Path)));
                    }
                }

                foreach (var directory in testStep.ReportDirectories)
                {
                    if (Directory.Exists(directory.Path))
                    {
                        var files = Directory.GetFiles(directory.Path, "*.*", SearchOption.AllDirectories);
                        foreach (var file in files)
                        {
                            filesToTransfer.Add(new FileInfo(file), new DirectoryInfo(directory.Path));
                        }
                    }
                }

                if (additionalFilesToInclude != null)
                {
                    foreach (var file in additionalFilesToInclude)
                    {
                        if (File.Exists(file))
                        {
                            filesToTransfer.Add(new FileInfo(file), new DirectoryInfo(Path.GetDirectoryName(file)));
                        }
                    }
                }

                if (testStep.ReportIncludesSystemLog)
                {
                    var logFile = ConsoleExecuteConstants.LogPath();
                    if (File.Exists(logFile))
                    {
                        filesToTransfer.Add(new FileInfo(logFile), new DirectoryInfo(Path.GetDirectoryName(logFile)));
                    }
                }

                m_ReportFileUploader(testStep.Order, filesToTransfer);

                sectionBuilder.AddInformationMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Uploaded report files for test step: {0}",
                        testStep.Order));
            }
            catch (Exception e)
            {
                sectionBuilder.AddWarningMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Failed to upload report files for test step: {0}. Error was: {1}",
                        testStep.Order,
                        e));
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ConsoleExecuteTestStepProcessor"/> class.
        /// </summary>
        /// <param name="testFileLocation">
        /// The function that takes the name of the test step and returns the full path to the directory containing the files for the 
        /// given test step.
        /// </param>
        /// <param name="reportFileUploader">
        /// The function that is used to upload the report files for the current test step.
        /// </param>
        /// <param name="diagnostics">The object that provides the diagnostics methods for the application.</param>
        /// <param name="runner">The object that is used to execute console applications.</param>
        /// <param name="fileSystem">The object that provides access to the file system.</param>
        /// <param name="sectionBuilder">The section builder.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="testFileLocation"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="reportFileUploader"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="diagnostics"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="runner"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="fileSystem"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="sectionBuilder"/> is <see langword="null" />.
        /// </exception>
        public ConsoleExecuteTestStepProcessor(
            RetrieveFileDataForTestStep testFileLocation,
            UploadReportFilesForTestStep reportFileUploader,
            SystemDiagnostics diagnostics,
            IRunConsoleApplications runner,
            IFileSystem fileSystem,
            ITestSectionBuilder sectionBuilder)
            : base(testFileLocation, reportFileUploader, diagnostics)
        {
            {
                Lokad.Enforce.Argument(() => runner);
                Lokad.Enforce.Argument(() => fileSystem);
                Lokad.Enforce.Argument(() => sectionBuilder);
            }

            m_Runner = runner;
            m_FileSystem = fileSystem;
            m_SectionBuilder = sectionBuilder;
        }
 /// <summary>
 /// Constructs a new active environment proxy.
 /// </summary>
 /// <param name="environment">The specification for the environment.</param>
 /// <param name="preTerminateEnvironment">The action executed just prior to terminating the environment.</param>
 /// <param name="postTerminateEnvironment">The action executed after terminating the environment.</param>
 /// <param name="commands">The object that provides the commands used to communicate with the environment.</param>
 /// <param name="notifications">The object that provides notifications from the environment.</param>
 /// <param name="uploads">The object that tracks the files available for upload.</param>
 /// <param name="sectionBuilder">
 /// The object used to write information to the report about the starting and stopping of the environment.
 /// </param>
 /// <returns>A new active environment proxy object.</returns>
 protected abstract IActiveEnvironment ConstructEnvironmentProxy(
     MachineDescription environment,
     Action preTerminateEnvironment,
     Action postTerminateEnvironment,
     IExecuteTestStepsCommands commands,
     ITestExecutionNotifications notifications,
     IStoreUploads uploads,
     ITestSectionBuilder sectionBuilder);
 /// <summary>
 /// Load the environment.
 /// </summary>
 /// <param name="environment">The specification for the environment.</param>
 /// <param name="pingTimeoutInMilliseconds">The number of milliseconds that the ping operation should wait for a response.</param>
 /// <param name="maximumWaitTimeInMilliseconds">
 ///     The number of milliseconds that the operation should wait for the machine to come online.
 /// </param>
 /// <param name="pingCycleTimeInMilliseconds">The amount of time the operation should wait between consecutive ping operations.</param>
 /// <param name="sectionBuilder">
 /// The object used to write information to the report about the starting and stopping of the environment.
 /// </param>
 /// <returns>An action that should be used to return the environment to its previous state in case the environment load fails.</returns>
 protected abstract Action LoadEnvironment(
     MachineDescription environment,
     int pingTimeoutInMilliseconds,
     int maximumWaitTimeInMilliseconds,
     int pingCycleTimeInMilliseconds,
     ITestSectionBuilder sectionBuilder);
        private void ShutdownVirtualMachine(MachineDescription environment, ITestSectionBuilder sectionBuilder)
        {
            var specification = environment as HypervMachineDescription;
            if (specification == null)
            {
                throw new InvalidEnvironmentSpecificationException();
            }

            // See if the host machine is alive
            var host = specification.HostMachineId;
            var hostSpecification = m_EnvironmentById(host);
            if (hostSpecification == null)
            {
                sectionBuilder.AddErrorMessage(
                            string.Format(
                                CultureInfo.InvariantCulture,
                                "Could not locate VM host: {0}",
                                hostSpecification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            Diagnostics.Log(
                LevelToLog.Debug,
                HyperVConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Terminating Hyper-V virtual machine {0} [image: {1}] on host {2}",
                    specification.Name,
                    specification.Image,
                    hostSpecification.Name));

            // Connect to the Hyper-V host for the given environment
            var virtualMachine = new HypervVirtualMachine(specification.Image);
            try
            {
                virtualMachine.Terminate();
            }
            catch (FailedToRestoreEnvironmentException)
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Failed to shut down virtual machine: {0}",
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw;
            }

            var killTime = DateTimeOffset.Now + TimeSpan.FromMilliseconds(GlobalConstants.DefaultMaximumMachineShutdownTime);
            while ((virtualMachine.State != HypervVirtualMachineState.TurnedOff) && (DateTimeOffset.Now <= killTime))
            {
                Thread.Sleep(10);
            }

            try
            {
                virtualMachine.RestoreToSnapshot(specification.SnapshotToReturnTo);
            }
            catch (FailedToRestoreEnvironmentException)
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Failed to restore virtual machine snapshot [{0}] for machine {1}",
                        specification.SnapshotToReturnTo,
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw;
            }

            Diagnostics.Log(
                LevelToLog.Debug,
                HyperVConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Hyper-V virtual machine {0} terminated",
                    specification.Name));

            sectionBuilder.AddInformationMessage(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Virtual machine shut down: {0}",
                    specification.NetworkName));
            sectionBuilder.FinalizeAndStore(true);
        }
        /// <summary>
        /// Creates a new active environment based on the given specification.
        /// </summary>
        /// <param name="environment">The specification that provides the configuration for the active environment.</param>
        /// <param name="sectionBuilder">
        /// The object used to write information to the report about the starting and stopping of the environment.
        /// </param>
        /// <param name="onUnload">The action that is executed upon test completion.</param>
        /// <returns>A new active environment.</returns>
        public IActiveEnvironment Load(
            MachineDescription environment,
            ITestSectionBuilder sectionBuilder,
            Action<string> onUnload)
        {
            {
                Lokad.Enforce.Argument(() => environment);
                Lokad.Enforce.Argument(() => onUnload);
            }

            Diagnostics.Log(
                LevelToLog.Trace,
                MachineConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Starting environment: {0}",
                    environment.Name));

            var pingTimeout = m_Configuration.HasValueFor(SharedConfigurationKeys.PingTimeoutInMilliseconds)
                ? m_Configuration.Value<int>(SharedConfigurationKeys.PingTimeoutInMilliseconds)
                : GlobalConstants.DefaultPingTimeoutInMilliseconds;

            var signInTimeout = m_Configuration.HasValueFor(SharedConfigurationKeys.MaximumNetworkSignInTimeInMilliseconds)
                ? m_Configuration.Value<int>(SharedConfigurationKeys.MaximumNetworkSignInTimeInMilliseconds)
                : GlobalConstants.DefaultMaximumNetworkSignInTimeInMilliseconds;

            var cycleTime = m_Configuration.HasValueFor(SharedConfigurationKeys.PingCycleTimeInMilliseconds)
                ? m_Configuration.Value<int>(SharedConfigurationKeys.PingCycleTimeInMilliseconds)
                : GlobalConstants.DefaultPingCycleTimeInMilliseconds;
            var emergencyShutdown = LoadEnvironment(environment, pingTimeout, signInTimeout, cycleTime, sectionBuilder);

            var endpoint = FindMachineEndpoint(environment.NetworkName, signInTimeout, cycleTime);
            if (endpoint == null)
            {
                Diagnostics.Log(
                    LevelToLog.Error,
                    MachineConstants.LogPrefix,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Could not find remote endpoint on environment: {0}",
                        environment.Name));

                emergencyShutdown();
                throw new CouldNotLoadEnvironmentException();
            }

            Diagnostics.Log(
                LevelToLog.Info,
                MachineConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Successfully started {0}",
                    environment.Name));

            var commands = m_Commands.CommandsFor<IExecuteTestStepsCommands>(endpoint);
            var notifications = m_Notifications.NotificationsFor<ITestExecutionNotifications>(endpoint);
            return ConstructEnvironmentProxy(
                environment,
                () => DisconnectCommunication(endpoint),
                () => onUnload(environment.Id),
                commands,
                notifications,
                m_Uploads,
                sectionBuilder);
        }
        /// <summary>
        /// Constructs a new active environment proxy.
        /// </summary>
        /// <param name="environment">The specification for the environment.</param>
        /// <param name="preTerminateEnvironment">The action executed just prior to terminating the environment.</param>
        /// <param name="postTerminateEnvironment">The action executed after terminating the environment.</param>
        /// <param name="commands">The object that provides the commands used to communicate with the environment.</param>
        /// <param name="notifications">The object that provides notifications from the environment.</param>
        /// <param name="uploads">The object that tracks the files available for upload.</param>
        /// <param name="sectionBuilder">
        /// The object used to write information to the report about the starting and stopping of the environment.
        /// </param>
        /// <returns>A new active environment proxy object.</returns>
        protected override IActiveEnvironment ConstructEnvironmentProxy(
            MachineDescription environment,
            Action preTerminateEnvironment,
            Action postTerminateEnvironment,
            IExecuteTestStepsCommands commands,
            ITestExecutionNotifications notifications,
            IStoreUploads uploads,
            ITestSectionBuilder sectionBuilder)
        {
            Action shutDownAction =
                () =>
                {
                    preTerminateEnvironment();
                    ShutdownVirtualMachine(environment, sectionBuilder);
                    postTerminateEnvironment();
                };

            return new ActiveHypervEnvironment(
                environment.Id,
                shutDownAction,
                commands,
                notifications,
                uploads);
        }
        /// <summary>
        /// Load the environment.
        /// </summary>
        /// <param name="environment">The specification for the environment.</param>
        /// <param name="pingTimeoutInMilliseconds">The number of milliseconds that the ping operation should wait for a response.</param>
        /// <param name="maximumWaitTimeInMilliseconds">
        ///     The number of milliseconds that the operation should wait for the machine to come online.
        /// </param>
        /// <param name="pingCycleTimeInMilliseconds">The amount of time the operation should wait between consecutive ping operations.</param>
        /// <param name="sectionBuilder">
        /// The object used to write information to the report about the starting and stopping of the environment.
        /// </param>
        /// <returns>An action that should be used to return the environment to its previous state in case the environment load fails.</returns>
        protected override Action LoadEnvironment(
            MachineDescription environment,
            int pingTimeoutInMilliseconds,
            int maximumWaitTimeInMilliseconds,
            int pingCycleTimeInMilliseconds,
            ITestSectionBuilder sectionBuilder)
        {
            var specification = environment as HypervMachineDescription;
            if (specification == null)
            {
                throw new InvalidEnvironmentSpecificationException();
            }

            // See if the host machine is alive
            var host = specification.HostMachineId;
            var hostSpecification = m_EnvironmentById(host);
            if (hostSpecification == null)
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Unable to locate host machine: {0}",
                        hostSpecification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            // See if the host is awake and if not try to wake it up.
            var physicalHostSpecification = hostSpecification as PhysicalMachineDescription;
            var canStartRemotely = physicalHostSpecification != null && physicalHostSpecification.CanStartRemotely;
            if (!MachineHelpers.WakeNetworkedMachineAndWaitForNetworkSignIn(
                hostSpecification.NetworkName,
                hostSpecification.MacAddress,
                Diagnostics,
                canStartRemotely,
                pingTimeoutInMilliseconds,
                maximumWaitTimeInMilliseconds,
                pingCycleTimeInMilliseconds))
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Unable to start host machine: {0}",
                        hostSpecification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            // Connect to the Hyper-V host for the given environment
            var virtualMachine = new HypervVirtualMachine(specification.Image);
            if (virtualMachine.State == HypervVirtualMachineState.Paused || virtualMachine.State == HypervVirtualMachineState.Running)
            {
                sectionBuilder.AddWarningMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Virtual machine running unexpectedly: {0}",
                        specification.NetworkName));
                sectionBuilder.AddWarningMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Resetting virtual machine: {0}",
                        specification.NetworkName));

                KillAndResetVirtualMachine(virtualMachine, specification);
            }

            virtualMachine.Start();

            Diagnostics.Log(
                LevelToLog.Debug,
                HyperVConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Started Hyper-V virtual machine {0} [image: {1}] on host {2}",
                    specification.Name,
                    specification.Image,
                    hostSpecification.Name));

            sectionBuilder.AddInformationMessage(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Started machine: {0}",
                    specification.NetworkName));

            return () =>
            {
                Diagnostics.Log(
                    LevelToLog.Debug,
                    HyperVConstants.LogPrefix,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Terminating Hyper-V virtual machine {0} [image: {1}] on host {2}",
                        specification.Name,
                        specification.Image,
                        hostSpecification.Name));

                KillAndResetVirtualMachine(virtualMachine, specification);

                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Terminated machine: {0}",
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);
            };
        }
        private bool DownloadTestData(
            EndpointId callingEndpoint,
            UploadToken token,
            string storageDirectory,
            ITestSectionBuilder builder,
            out string testFile)
        {
            testFile = string.Empty;
            try
            {
                testFile = DownloadTestData(callingEndpoint, token, storageDirectory);

                m_Diagnostics.Log(
                    LevelToLog.Debug,
                    ExecutorServiceConstants.LogPrefix,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.Log_Messages_DownloadedTestData_WithFile,
                        testFile));
                builder.AddInformationMessage(Resources.ReportSection_Info_DownloadedTestData);
            }
            catch (Exception)
            {
                builder.AddErrorMessage(Resources.ReportSection_Error_FailedToDownloadTestData);
                builder.FinalizeAndStore(false);
                m_TestExecutionEvents.RaiseOnTestCompletion(TestExecutionResult.Failed);

                return false;
            }

            return true;
        }
Esempio n. 11
0
        private static void RollbackExecutedStepsOnFailure(
            List<Tuple<TestStep, IParticipateInCleanUp>> executedSteps,
            SystemDiagnostics diagnostics,
            ITestSectionBuilder sectionWriter)
        {
            try
            {
                for (int i = executedSteps.Count - 1; i > -1; i--)
                {
                    var pair = executedSteps[i];
                    diagnostics.Log(
                        LevelToLog.Info,
                        ExecutorConstants.LogPrefix,
                        string.Format(
                            CultureInfo.InvariantCulture,
                            Resources.Log_Messages_CleaningUpTestStep_WithStepAndTestStepType,
                            pair.Item1.Order,
                            pair.Item1.GetType()));

                    pair.Item2.CleanUp(pair.Item1);
                }
            }
            catch (Exception e)
            {
                diagnostics.Log(
                    LevelToLog.Error,
                    ExecutorConstants.LogPrefix,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.Log_Messages_FailedToCleanUp_WithError,
                        e));

                sectionWriter.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.Reporting_TestExecution_CleanupFailed_WithException,
                        e));
            }
        }
Esempio n. 12
0
        /// <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;
            }
        }
        /// <summary>
        /// Load the environment.
        /// </summary>
        /// <param name="environment">The specification for the environment.</param>
        /// <param name="pingTimeoutInMilliseconds">The number of milliseconds that the ping operation should wait for a response.</param>
        /// <param name="maximumWaitTimeInMilliseconds">
        ///     The number of milliseconds that the operation should wait for the machine to come online.
        /// </param>
        /// <param name="pingCycleTimeInMilliseconds">The amount of time the operation should wait between consecutive ping operations.</param>
        /// <param name="sectionBuilder">
        /// The object used to write information to the report about the starting and stopping of the environment.
        /// </param>
        /// <returns>An action that should be used to return the environment to its previous state in case the environment load fails.</returns>
        protected override Action LoadEnvironment(
            MachineDescription environment,
            int pingTimeoutInMilliseconds,
            int maximumWaitTimeInMilliseconds,
            int pingCycleTimeInMilliseconds,
            ITestSectionBuilder sectionBuilder)
        {
            var specification = environment as PhysicalMachineDescription;
            if (specification == null)
            {
                throw new InvalidEnvironmentSpecificationException();
            }

            if (!MachineHelpers.WakeNetworkedMachineAndWaitForNetworkSignIn(
                specification.NetworkName,
                specification.MacAddress,
                Diagnostics,
                specification.CanStartRemotely,
                pingTimeoutInMilliseconds,
                maximumWaitTimeInMilliseconds,
                pingCycleTimeInMilliseconds))
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Unable to start machine: {0}",
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            sectionBuilder.AddInformationMessage(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Started machine: {0}",
                    specification.NetworkName));

            return () =>
            {
                // Do nothing really. We can't shut machines down remotely.
            };
        }
        /// <summary>
        /// Constructs a new active environment proxy.
        /// </summary>
        /// <param name="environment">The specification for the environment.</param>
        /// <param name="preTerminateEnvironment">The action executed just prior to terminating the environment.</param>
        /// <param name="postTerminateEnvironment">The action executed after terminating the environment.</param>
        /// <param name="commands">The object that provides the commands used to communicate with the environment.</param>
        /// <param name="notifications">The object that provides notifications from the environment.</param>
        /// <param name="uploads">The object that tracks the files available for upload.</param>
        /// <param name="sectionBuilder">
        /// The object used to write information to the report about the starting and stopping of the environment.
        /// </param>
        /// <returns>A new active environment proxy object.</returns>
        protected override IActiveEnvironment ConstructEnvironmentProxy(
            MachineDescription environment,
            Action preTerminateEnvironment,
            Action postTerminateEnvironment,
            IExecuteTestStepsCommands commands,
            ITestExecutionNotifications notifications,
            IStoreUploads uploads,
            ITestSectionBuilder sectionBuilder)
        {
            Action shutDownAction =
                () =>
                {
                    preTerminateEnvironment();
                    postTerminateEnvironment();

                    sectionBuilder.AddInformationMessage(
                        string.Format(
                            CultureInfo.InvariantCulture,
                            "Terminated machine: {0}",
                            environment.NetworkName));
                    sectionBuilder.FinalizeAndStore(true);
                };

            return new ActivePhysicalMachineEnvironment(
                environment.Id,
                shutDownAction,
                commands,
                notifications,
                uploads);
        }