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}"); } }
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 }
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 }
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); }
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); }