public void Initialize()
        {
            // Validation doesn't look at the files specified, only settings
            _package = new TestPackage("any.dll");

            _runtimeService = Substitute.For <IRuntimeFrameworkService>();
            _runtimeService.IsAvailable("net-2.0").Returns(true);
            _runtimeService.IsAvailable("net-4.0").Returns(true);
            _runtimeService.IsAvailable("net-4.5").Returns(true);
            _runtimeService.IsAvailable(CURRENT_RUNTIME).Returns(true);
            _runtimeService.IsAvailable("netcore-3.0").Returns(true); // Not actually available yet, but used to test

            _validator = new TestPackageValidator(_runtimeService);
        }
        /// <summary>
        /// Examine package settings to see if they are valid. An
        /// <see cref="NUnitEngineException"> is thrown if errors
        /// are found.
        /// </summary>
        /// <param name="package">The package whose settings are to be validated</param>
        public void ValidatePackageSettings(TestPackage package)
        {
            var sb = new StringBuilder();

            var frameworkSetting = package.GetSetting(EnginePackageSettings.RequestedRuntimeFramework, "");
            var runAsX86         = package.GetSetting(EnginePackageSettings.RunAsX86, false);

            if (frameworkSetting.Length > 0)
            {
                // Check requested framework is actually available
                if (!_runtimeService.IsAvailable(frameworkSetting))
                {
                    sb.Append($"\n* The requested framework {frameworkSetting} is unknown or not available.\n");
                }
            }

            // At this point, any unsupported settings in the TestPackage were
            // put there by the user, so we consider the package invalid. This
            // will be checked again as each project package is expanded and
            // treated as a warning in that case.
            foreach (string setting in package.Settings.Keys)
            {
                if (EnginePackageSettings.IsObsoleteSetting(setting))
                {
                    sb.Append($"\n* The {setting} setting is no longer supported.\n");
                }
            }

            if (sb.Length > 0)
            {
                throw new NUnitEngineException($"The following errors were detected in the TestPackage:\n{sb}");
            }
        }
Beispiel #3
0
        public ITestAgent GetAgent(TestPackage package)
        {
            // Target Runtime must be specified by this point
            string runtimeSetting = package.GetSetting(EnginePackageSettings.TargetRuntimeFramework, "");

            Guard.OperationValid(runtimeSetting.Length > 0, "LaunchAgentProcess called with no runtime specified");

            // If target runtime is not available, something went wrong earlier.
            // We list all available frameworks to use in debugging.
            var targetRuntime = RuntimeFramework.Parse(runtimeSetting);

            if (!_runtimeService.IsAvailable(targetRuntime.Id))
            {
                string msg = $"The {targetRuntime} framework is not available.\r\nAvailable frameworks:";
                foreach (var runtime in RuntimeFramework.AvailableFrameworks)
                {
                    msg += $" {runtime}";
                }
                throw new ArgumentException(msg);
            }

            var agentId      = Guid.NewGuid();
            var agentProcess = new AgentProcess(this, package, agentId);

            agentProcess.Exited += (sender, e) => OnAgentExit((Process)sender, agentId);

            agentProcess.Start();
            log.Debug("Launched Agent process {0} - see nunit-agent_{0}.log", agentProcess.Id);
            log.Debug("Command line: \"{0}\" {1}", agentProcess.StartInfo.FileName, agentProcess.StartInfo.Arguments);

            _agentStore.AddAgent(agentId, agentProcess);

            log.Debug($"Waiting for agent {agentId:B} to register");

            const int pollTime = 200;

            // Increase the timeout to give time to attach a debugger
            bool debug = package.GetSetting(EnginePackageSettings.DebugAgent, false) ||
                         package.GetSetting(EnginePackageSettings.PauseBeforeRun, false);

            int waitTime = debug ? DEBUG_TIMEOUT : NORMAL_TIMEOUT;

            // Wait for agent registration based on the agent actually getting processor time to avoid falling over
            // under process starvation.
            while (waitTime > agentProcess.TotalProcessorTime.TotalMilliseconds && !agentProcess.HasExited)
            {
                Thread.Sleep(pollTime);

                if (_agentStore.IsReady(agentId, out var agent))
                {
                    log.Debug($"Returning new agent {agentId:B}");

                    return(new TestAgentRemotingProxy(agent, agentId));
                }
            }

            return(null);
        }
        // Any Errors thrown from this method indicate that the client
        // runner is putting invalid values into the package.
        public void Validate(TestPackage package)
        {
#if !NETSTANDARD2_0  // TODO: How do we validate runtime framework for .NET Standard 2.0?
            var frameworkSetting = package.GetSetting(EnginePackageSettings.RequestedRuntimeFramework, "");
            var runAsX86         = package.GetSetting(EnginePackageSettings.RunAsX86, false);

            if (frameworkSetting.Length > 0)
            {
                // Check requested framework is actually available
                if (!_runtimeService.IsAvailable(frameworkSetting))
                {
                    throw new NUnitEngineException($"The requested framework {frameworkSetting} is unknown or not available.");
                }
            }
#endif
        }
Beispiel #5
0
        public ITestAgent GetAgent(TestPackage package)
        {
            // Target Runtime must be specified by this point
            string runtimeSetting = package.GetSetting(EnginePackageSettings.TargetRuntimeFramework, "");

            Guard.OperationValid(runtimeSetting.Length > 0, "LaunchAgentProcess called with no runtime specified");

            var targetRuntime = RuntimeFramework.Parse(runtimeSetting);

            if (!_runtimeService.IsAvailable(targetRuntime.Id))
            {
                throw new ArgumentException(
                          string.Format("The {0} framework is not available", targetRuntime),
                          "framework");
            }

            // TODO: Decide if we should reuse agents
            return(CreateRemoteAgent(package, targetRuntime));
        }
        // Any Errors thrown from this method indicate that the client
        // runner is putting invalid values into the package.
        public void Validate(TestPackage package)
        {
#if !NETSTANDARD2_0  // TODO: How do we validate runtime framework for .NET Standard 2.0?
            var processModel     = package.GetSetting(EnginePackageSettings.ProcessModel, "Default").ToLower();
            var runningInProcess = processModel == "inprocess";
            var frameworkSetting = package.GetSetting(EnginePackageSettings.RuntimeFramework, "");
            var runAsX86         = package.GetSetting(EnginePackageSettings.RunAsX86, false);

            if (frameworkSetting.Length > 0)
            {
                // Check requested framework is actually available
                if (!_runtimeService.IsAvailable(frameworkSetting))
                {
                    throw new NUnitEngineException($"The requested framework {frameworkSetting} is unknown or not available.");
                }

                // If running in process, check requested framework is compatible
                if (runningInProcess)
                {
                    var currentFramework = RuntimeFramework.CurrentFramework;

                    RuntimeFramework requestedFramework;
                    if (!RuntimeFramework.TryParse(frameworkSetting, out requestedFramework))
                    {
                        throw new NUnitEngineException("Invalid or unknown framework requested: " + frameworkSetting);
                    }

                    if (!currentFramework.Supports(requestedFramework))
                    {
                        throw new NUnitEngineException(string.Format(
                                                           "Cannot run {0} framework in process already running {1}.", frameworkSetting, currentFramework));
                    }
                }
            }

            if (runningInProcess && runAsX86 && IntPtr.Size == 8)
            {
                throw new NUnitEngineException("Cannot run tests in process - a 32 bit process is required.");
            }
#endif
        }
Beispiel #7
0
        public ITestAgent GetAgent(TestPackage package)
        {
            // Target Runtime must be specified by this point
            string runtimeSetting = package.GetSetting(EnginePackageSettings.TargetRuntimeFramework, "");

            Guard.OperationValid(runtimeSetting.Length > 0, "LaunchAgentProcess called with no runtime specified");

            // If target runtime is not available, something went wrong earlier
            var targetRuntime = RuntimeFramework.Parse(runtimeSetting);

            if (!_runtimeService.IsAvailable(targetRuntime.Id))
            {
                throw new ArgumentException(
                          string.Format("The {0} framework is not available", targetRuntime),
                          "framework");
            }

            var    agentId      = Guid.NewGuid();
            string agencyUrl    = targetRuntime.FrameworkName.Identifier == ".NETFramework" ? RemotingUrl : TcpEndPoint;
            var    agentProcess = CreateAgentProcess(agentId, agencyUrl, package);

            agentProcess.Exited += (sender, e) => OnAgentExit((Process)sender);

            agentProcess.Start();
            log.Debug("Launched Agent process {0} - see testcentric-agent_{0}.log", agentProcess.Id);
            log.Debug("Command line: \"{0}\" {1}", agentProcess.StartInfo.FileName, agentProcess.StartInfo.Arguments);

            _agentStore.AddAgent(agentId, agentProcess);

            log.Debug($"Waiting for agent {agentId:B} to register");

            const int pollTime = 200;

            // Increase the timeout to give time to attach a debugger
            bool debug = package.GetSetting(EnginePackageSettings.DebugAgent, false) ||
                         package.GetSetting(EnginePackageSettings.PauseBeforeRun, false);

            int waitTime = debug ? DEBUG_TIMEOUT : NORMAL_TIMEOUT;

            // Wait for agent registration based on the agent actually getting processor time to avoid falling over
            // under process starvation.
            while (waitTime > agentProcess.TotalProcessorTime.TotalMilliseconds && !agentProcess.HasExited)
            {
                Thread.Sleep(pollTime);

                if (_agentStore.IsReady(agentId, out var agent))
                {
                    log.Debug($"Returning new agent {agentId:B}");

                    switch (targetRuntime.Runtime.FrameworkIdentifier)
                    {
                    case FrameworkIdentifiers.NetFramework:
                        return(new TestAgentRemotingProxy(agent, agentId));

                    case FrameworkIdentifiers.NetCoreApp:
                        return(agent);

                    default:
                        throw new InvalidOperationException($"Invalid runtime: {targetRuntime.Runtime.FrameworkIdentifier}");
                    }
                }
            }

            return(null);
        }
Beispiel #8
0
        private Process LaunchAgentProcess(TestPackage package, Guid agentId)
        {
            string runtimeSetting = package.GetSetting(EnginePackageSettings.RuntimeFramework, "");

            // TEMPORARY Guard in preparation for removing Runtime.Any
            Guard.OperationValid(runtimeSetting.Length > 0, "LaunchAgentProcess called with no runtime specified");

            var targetRuntime = RuntimeFramework.Parse(runtimeSetting);

            bool   useX86Agent     = package.GetSetting(EnginePackageSettings.RunAsX86, false);
            bool   debugTests      = package.GetSetting(EnginePackageSettings.DebugTests, false);
            bool   debugAgent      = package.GetSetting(EnginePackageSettings.DebugAgent, false);
            string traceLevel      = package.GetSetting(EnginePackageSettings.InternalTraceLevel, "Off");
            bool   loadUserProfile = package.GetSetting(EnginePackageSettings.LoadUserProfile, false);
            string workDirectory   = package.GetSetting(EnginePackageSettings.WorkDirectory, string.Empty);

            var agentArgs = new StringBuilder();

            // Set options that need to be in effect before the package
            // is loaded by using the command line.
            agentArgs.Append("--pid=").Append(Process.GetCurrentProcess().Id);
            if (traceLevel != "Off")
            {
                agentArgs.Append(" --trace:").EscapeProcessArgument(traceLevel);
            }
            if (debugAgent)
            {
                agentArgs.Append(" --debug-agent");
            }
            if (workDirectory != string.Empty)
            {
                agentArgs.Append(" --work=").EscapeProcessArgument(workDirectory);
            }

            log.Info("Getting {0} agent for use under {1}", useX86Agent ? "x86" : "standard", targetRuntime);

            if (!_runtimeService.IsAvailable(targetRuntime.Id))
            {
                throw new ArgumentException(
                          string.Format("The {0} framework is not available", targetRuntime),
                          "framework");
            }

            string agentExePath = GetTestAgentExePath(useX86Agent);

            if (!File.Exists(agentExePath))
            {
                throw new FileNotFoundException(
                          $"{Path.GetFileName(agentExePath)} could not be found.", agentExePath);
            }

            log.Debug("Using testcentric-agent at " + agentExePath);

            Process p = new Process();

            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow  = true;
            p.EnableRaisingEvents       = true;
            p.Exited += (sender, e) => OnAgentExit((Process)sender, agentId);
            string arglist = agentId.ToString() + " " + ServerUrl + " " + agentArgs;

            targetRuntime = ServiceContext.GetService <RuntimeFrameworkService>().GetBestAvailableFramework(targetRuntime);

            if (targetRuntime.Runtime == Runtime.Mono)
            {
                p.StartInfo.FileName = targetRuntime.MonoExePath;
                string monoOptions = "--runtime=v" + targetRuntime.ClrVersion.ToString(3);
                if (debugTests || debugAgent)
                {
                    monoOptions += " --debug";
                }
                p.StartInfo.Arguments = string.Format("{0} \"{1}\" {2}", monoOptions, agentExePath, arglist);
            }
            else if (targetRuntime.Runtime == Runtime.Net)
            {
                p.StartInfo.FileName = agentExePath;
                // Override the COMPLUS_Version env variable, this would cause CLR meta host to run a CLR of the specific version
                string envVar = "v" + targetRuntime.ClrVersion.ToString(3);
                p.StartInfo.EnvironmentVariables["COMPLUS_Version"] = envVar;
                // Leave a marker that we have changed this variable, so that the agent could restore it for any code or child processes running within the agent
                string cpvOriginal = Environment.GetEnvironmentVariable("COMPLUS_Version");
                p.StartInfo.EnvironmentVariables["TestAgency_COMPLUS_Version_Original"] = string.IsNullOrEmpty(cpvOriginal) ? "NULL" : cpvOriginal;
                p.StartInfo.Arguments       = arglist;
                p.StartInfo.LoadUserProfile = loadUserProfile;
            }
            else
            {
                p.StartInfo.FileName  = agentExePath;
                p.StartInfo.Arguments = arglist;
            }

            p.Start();
            log.Debug("Launched Agent process {0} - see testcentric-agent_{0}.log", p.Id);
            log.Debug("Command line: \"{0}\" {1}", p.StartInfo.FileName, p.StartInfo.Arguments);

            _agents.Start(agentId, p);
            return(p);
        }