public void GetEnvironmentVariablesWithoutEnvVarNodeInRunSettingsShouldReturnNull()
        {
            string runSettingsXml = @"<RunSettings>
									   <RunConfiguration>
									   </RunConfiguration>
									  </RunSettings>"                                    ;

            var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml);

            Assert.IsNull(envVars);
        }
        public void GetEnvironmentVariablesWithEmptyVariablesInRunSettingsShouldReturnEmptyDictionary()
        {
            string runSettingsXml = @"<RunSettings>
									   <RunConfiguration>
										 <EnvironmentVariables>
										 </EnvironmentVariables>
									   </RunConfiguration>
									  </RunSettings>"                                    ;

            var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml);

            Assert.AreEqual(0, envVars.Count);
        }
        public void GetEnvironmentVariablesWithDuplicateEnvValuesInRunSettingsShouldReturnValidDictionary()
        {
            string runSettingsXml = @"<RunSettings>
									   <RunConfiguration>
										  <EnvironmentVariables>
											 <RANDOM_PATH>C:\temp</RANDOM_PATH>
											 <RANDOM_PATH>C:\temp2</RANDOM_PATH>
										  </EnvironmentVariables>
									   </RunConfiguration>
									  </RunSettings>"                                    ;

            var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettingsXml);

            Assert.AreEqual(1, envVars.Count);
            Assert.AreEqual(@"C:\temp", envVars["RANDOM_PATH"]);
        }
        /// <summary>
        /// Ensures that the engine is ready for test operations. Usually includes starting up the
        /// test host process.
        /// </summary>
        ///
        /// <param name="sources">List of test sources.</param>
        /// <param name="runSettings">Run settings to be used.</param>
        ///
        /// <returns>
        /// Returns true if the communication is established b/w runner and host, false otherwise.
        /// </returns>
        public virtual bool SetupChannel(IEnumerable <string> sources, string runSettings)
        {
            this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();

            //System.Diagnostics.Debugger.Launch();
            //System.Diagnostics.Debugger.Break();

            if (this.initialized)
            {
                return(true);
            }

            var connTimeout = EnvironmentHelper.GetConnectionTimeout();

            this.testHostProcessStdError = string.Empty;
            TestHostConnectionInfo testHostConnectionInfo = this.TestHostManager.GetTestHostConnectionInfo();

            var portNumber = 0;

            if (testHostConnectionInfo.Role == ConnectionRole.Client)
            {
                portNumber = this.RequestSender.InitializeCommunication();
                testHostConnectionInfo.Endpoint += portNumber;
            }

            var processId      = this.processHelper.GetCurrentProcessId();
            var connectionInfo = new TestRunnerConnectionInfo()
            {
                Port            = portNumber,
                ConnectionInfo  = testHostConnectionInfo,
                RunnerProcessId = processId,
                LogFile         = this.GetTimestampedLogFile(EqtTrace.LogFile),
                TraceLevel      = (int)EqtTrace.TraceLevel
            };

            // Subscribe to test host events.
            this.TestHostManager.HostLaunched += this.TestHostManagerHostLaunched;
            this.TestHostManager.HostExited   += this.TestHostManagerHostExited;

            // Get environment variables from run settings.
            var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettings);

            // Get the test process start info.
            var hostStartInfo = this.TestHostManager.GetTestHostProcessStartInfo(
                sources,
                envVars,
                connectionInfo);


            EqtTrace.Verbose("DefaultTestHostmanager::Received path is: " + hostStartInfo.FileName);

            if (!File.Exists(hostStartInfo.FileName))
            {
                // Somehow can not set path to file in Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DefaultTestHostManager::GetTestHostProcessStartInfo()
                // :( :( :( Why ?? :(
                var fileName         = Path.GetFileName(hostStartInfo.FileName);
                var directory        = Path.GetDirectoryName(hostStartInfo.FileName);
                var frameworkMoniker = fileName.Split('.');

                EqtTrace.Verbose("DefaultTestHostmanager::[1] directory is: " + directory);

                while (directory.Contains("\\TestHost"))
                {
                    directory = directory.Replace("\\TestHost", "");
                }

                EqtTrace.Verbose("DefaultTestHostmanager::[2] directory is: " + directory);

                if (directory.Contains("\\TestsHosts") == false)
                {
                    fileName = Path.Combine(directory, "TestsHosts", frameworkMoniker[1], "win7-x86", fileName);
                }
                else
                {
                    fileName = Path.Combine(directory, frameworkMoniker[1], "win7-x86", fileName);
                }

                hostStartInfo.FileName = fileName;

                EqtTrace.Verbose("DefaultTestHostmanager::Fixed path to: " + hostStartInfo.FileName);
            }

            var testHostStartInfo = this.UpdateTestProcessStartInfo(hostStartInfo);

            try
            {
                // Launch the test host.
                var hostLaunchedTask = this.TestHostManager.LaunchTestHostAsync(
                    testHostStartInfo,
                    this.CancellationTokenSource.Token);
                this.testHostLaunched = hostLaunchedTask.Result;

                if (this.testHostLaunched && testHostConnectionInfo.Role == ConnectionRole.Host)
                {
                    // If test runtime is service host, try to poll for connection as client.
                    this.RequestSender.InitializeCommunication();
                }
            }
            catch (Exception ex)
            {
                EqtTrace.Error("ProxyOperationManager: Failed to launch testhost :{0}", ex);

                this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();
                throw new TestPlatformException(string.Format(
                                                    CultureInfo.CurrentUICulture,
                                                    CrossPlatEngineResources.FailedToLaunchTestHost,
                                                    ex.ToString()));
            }

            // Warn the user that execution will wait for debugger attach.
            var hostDebugEnabled       = Environment.GetEnvironmentVariable("VSTEST_HOST_DEBUG");
            var nativeHostDebugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_NATIVE_DEBUG");

            if (!string.IsNullOrEmpty(hostDebugEnabled) && hostDebugEnabled.Equals("1", StringComparison.Ordinal) ||
                new PlatformEnvironment().OperatingSystem.Equals(PlatformOperatingSystem.Windows) &&
                !string.IsNullOrEmpty(nativeHostDebugEnabled) && nativeHostDebugEnabled.Equals("1", StringComparison.Ordinal))
            {
                ConsoleOutput.Instance.WriteLine(
                    CrossPlatEngineResources.HostDebuggerWarning,
                    OutputLevel.Warning);

                ConsoleOutput.Instance.WriteLine(
                    string.Format(
                        "Process Id: {0}, Name: {1}",
                        this.testHostProcessId,
                        this.processHelper.GetProcessName(this.testHostProcessId)),
                    OutputLevel.Information);

                // Increase connection timeout when debugging is enabled.
                connTimeout *= 5;
            }

            // If test host does not launch then throw exception, otherwise wait for connection.
            if (!this.testHostLaunched ||
                !this.RequestSender.WaitForRequestHandlerConnection(
                    connTimeout * 1000,
                    this.CancellationTokenSource.Token))
            {
                EqtTrace.Verbose($"Test host failed to start Test host launched:{testHostLaunched} test host exited: {testHostExited.IsSet}");
                // Throw a test platform exception with the appropriate message if user requested cancellation.
                this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();

                // Throw a test platform exception along with the error messages from the test if the test host exited unexpectedly
                // before communication was established.
                this.ThrowOnTestHostExited(this.testHostExited.IsSet);

                // Throw a test platform exception stating the connection to test could not be established even after waiting
                // for the configure timeout period.
                this.ThrowExceptionOnConnectionFailure(connTimeout);
            }

            // Handling special case for dotnet core projects with older test hosts.
            // Older test hosts are not aware of protocol version check, hence we should not be
            // sending VersionCheck message to these test hosts.
            this.CompatIssueWithVersionCheckAndRunsettings();

            if (this.versionCheckRequired)
            {
                this.RequestSender.CheckVersionWithTestHost();
            }

            this.initialized = true;

            return(true);
        }
        /// <summary>
        /// Ensure that the engine is ready for test operations.
        /// Usually includes starting up the test host process.
        /// </summary>
        /// <param name="sources">
        /// List of test sources.
        /// </param>
        /// <param name="cancellationToken">
        /// </param>
        /// <returns>
        /// Returns true if Communation is established b/w runner and host
        /// </returns>
        public virtual bool SetupChannel(IEnumerable <string> sources, string runSettings)
        {
            this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();
            var connTimeout = EnvironmentHelper.GetConnectionTimeout();

            if (!this.initialized)
            {
                this.testHostProcessStdError = string.Empty;
                TestHostConnectionInfo testHostConnectionInfo = this.testHostManager.GetTestHostConnectionInfo();
                var portNumber = 0;

                if (testHostConnectionInfo.Role == ConnectionRole.Client)
                {
                    portNumber = this.RequestSender.InitializeCommunication();
                    testHostConnectionInfo.Endpoint += portNumber;
                }

                var processId      = this.processHelper.GetCurrentProcessId();
                var connectionInfo = new TestRunnerConnectionInfo {
                    Port = portNumber, ConnectionInfo = testHostConnectionInfo, RunnerProcessId = processId, LogFile = this.GetTimestampedLogFile(EqtTrace.LogFile), TraceLevel = (int)EqtTrace.TraceLevel
                };

                // Subscribe to TestHost Event
                this.testHostManager.HostLaunched += this.TestHostManagerHostLaunched;
                this.testHostManager.HostExited   += this.TestHostManagerHostExited;

                // Get envVars from run settings
                var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettings);

                // Get the test process start info
                var testHostStartInfo = this.UpdateTestProcessStartInfo(this.testHostManager.GetTestHostProcessStartInfo(sources, envVars, connectionInfo));
                try
                {
                    // Launch the test host.
                    var hostLaunchedTask = this.testHostManager.LaunchTestHostAsync(testHostStartInfo, this.CancellationTokenSource.Token);
                    this.testHostLaunched = hostLaunchedTask.Result;

                    if (this.testHostLaunched && testHostConnectionInfo.Role == ConnectionRole.Host)
                    {
                        // If test runtime is service host, try to poll for connection as client
                        this.RequestSender.InitializeCommunication();
                    }
                }
                catch (Exception ex)
                {
                    EqtTrace.Error("ProxyOperationManager: Failed to launch testhost :{0}", ex);

                    this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();
                    throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CrossPlatEngineResources.FailedToLaunchTestHost, ex.ToString()));
                }

                // Warn the user that execution will wait for debugger attach.
                var hostDebugEnabled       = Environment.GetEnvironmentVariable("VSTEST_HOST_DEBUG");
                var nativeHostDebugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_NATIVE_DEBUG");

                if (!string.IsNullOrEmpty(hostDebugEnabled) && hostDebugEnabled.Equals("1", StringComparison.Ordinal) ||
                    new PlatformEnvironment().OperatingSystem.Equals(PlatformOperatingSystem.Windows) &&
                    !string.IsNullOrEmpty(nativeHostDebugEnabled) && nativeHostDebugEnabled.Equals("1", StringComparison.Ordinal))
                {
                    ConsoleOutput.Instance.WriteLine(CrossPlatEngineResources.HostDebuggerWarning, OutputLevel.Warning);
                    ConsoleOutput.Instance.WriteLine(
                        string.Format("Process Id: {0}, Name: {1}", this.testHostProcessId, this.processHelper.GetProcessName(this.testHostProcessId)),
                        OutputLevel.Information);

                    // Increase connection timeout when debugging is enabled.
                    connTimeout *= 5;
                }

                // If TestHost does not launch then throw exception
                // If Testhost launches, wait for connection.
                if (!this.testHostLaunched ||
                    !this.RequestSender.WaitForRequestHandlerConnection(connTimeout * 1000, this.CancellationTokenSource.Token))
                {
                    // Throw a test platform exception with the appropriate message if user requested cancellation
                    this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested();

                    // Throw a test platform exception along with the error messages from the test if the test host exited unexpectedly
                    // before communication was established
                    this.ThrowOnTestHostExited(this.testHostExited.IsSet);

                    // Throw a test platform exception stating the connection to test could not be established even after waiting
                    // for the configure timeout period
                    this.ThrowExceptionOnConnectionFailure(connTimeout);
                }

                // Handling special case for dotnet core projects with older test hosts
                // Older test hosts are not aware of protocol version check
                // Hence we should not be sending VersionCheck message to these test hosts
                this.CompatIssueWithVersionCheckAndRunsettings();

                if (this.versionCheckRequired)
                {
                    this.RequestSender.CheckVersionWithTestHost();
                }

                this.initialized = true;
            }

            return(true);
        }