public bool CanSupportRole(UnrealSessionRole Role, ref List <string> Reasons) { if (Role.RoleType.UsesEditor() && UnrealPath == null) { Reasons.Add(string.Format("Role {0} wants editor but no path to Unreal exists", Role)); return(false); } // null platform. Need a better way of specifying this if (Role.IsNullRole()) { return(true); } // Query our build list if (Role.Platform != null) { var MatchingBuilds = GetMatchingBuilds(Role.RoleType, Role.Platform.Value, Role.Configuration, Role.RequiredBuildFlags); if (MatchingBuilds.Count() > 0) { return(true); } } Reasons.Add(string.Format("No build at {0} that matches {1}", string.Join(",", BuildPaths), Role.ToString())); return(false); }
/// <summary> /// Constructor, all values must be provided /// </summary> /// <param name="InSessionRole"></param> /// <param name="InAppInstance"></param> /// <param name="InArtifactPath"></param> /// <param name="InLogSummary"></param> public UnrealRoleArtifacts(UnrealSessionRole InSessionRole, IAppInstance InAppInstance, string InArtifactPath, string InLogPath, UnrealLogParser InLog) { SessionRole = InSessionRole; AppInstance = InAppInstance; ArtifactPath = InArtifactPath; LogPath = InLogPath; LogParser = InLog; }
/// <summary> /// Apply our options to the provided app config /// </summary> /// <param name="AppConfig"></param> /// <returns></returns> public virtual void ApplyToConfig(UnrealAppConfig AppConfig, UnrealSessionRole ConfigRole, IEnumerable <UnrealSessionRole> OtherRoles) { if (AppConfig.ProcessType.IsClient()) { if (Nullrhi) { AppConfig.CommandLine += " -nullrhi"; } else { if (AppConfig.Platform == UnrealTargetPlatform.Win64 || AppConfig.Platform == UnrealTargetPlatform.Mac) { if (!IgnoreDefaultResolutionAndWindowMode) { if (Globals.Params.ToString().Contains("-resx") == false) { AppConfig.CommandLine += String.Format(" -ResX={0} -ResY={1}", ResX, ResY); } if (WindowMode == EWindowMode.Windowed || Windowed) { AppConfig.CommandLine += " -windowed"; } else if (WindowMode == EWindowMode.Fullscreen) { AppConfig.CommandLine += " -fullscreen"; } else if (WindowMode == EWindowMode.WindowedFullscreen) // Proper -windowedfullscreen flag does not exist and some platforms treat both modes as the same. { AppConfig.CommandLine += " -fullscreen"; } else { Log.Warning("Test config uses an unsupported WindowMode: {0}! WindowMode not set.", Enum.GetName(typeof(EWindowMode), WindowMode)); } } } if (ScreenshotPeriod > 0 && Nullrhi == false) { AppConfig.CommandLine += string.Format(" -gauntlet.screenshotperiod={0}", ScreenshotPeriod); } } } // use -log on servers so we get a window.. if (AppConfig.ProcessType.IsServer()) { AppConfig.CommandLine += " -log"; } if (Attended == false) { AppConfig.CommandLine += " -unattended"; } AppConfig.CommandLine += " -stdout -AllowStdOutLogVerbosity"; }
/// <summary> /// Installs and launches all of our roles and returns an UnrealSessonInstance that represents the aggregate /// of all of these processes. Will perform retries if errors with devices are encountered so this is a "best /// attempt" at running with the devices provided /// </summary> /// <returns></returns> public UnrealSessionInstance LaunchSession() { SessionInstance = null; // tries to find devices and launch our session. Will loop until we succeed, we run out of devices/retries, or // something fatal occurs.. while (SessionInstance == null && Globals.CancelSignalled == false) { int Retries = 5; int RetryWait = 120; IEnumerable <UnrealSessionRole> RolesNeedingDevices = SessionRoles.Where(R => R.IsNullRole() == false); while (ReservedDevices.Count() < RolesNeedingDevices.Count()) { // get devices TryReserveDevices(); if (Globals.CancelSignalled) { break; } // if we failed to get enough devices, show a message and wait if (ReservedDevices.Count() != SessionRoles.Count()) { if (Retries == 0) { throw new AutomationException("Unable to acquire all devices for test."); } Log.Info("\nUnable to find enough device(s). Waiting {0} secs (retries left={1})\n", RetryWait, --Retries); Thread.Sleep(RetryWait * 1000); } } if (Globals.CancelSignalled) { return(null); } Dictionary <IAppInstall, UnrealSessionRole> InstallsToRoles = new Dictionary <IAppInstall, UnrealSessionRole>(); // create a copy of our list IEnumerable <ITargetDevice> DevicesToInstallOn = ReservedDevices.ToArray(); bool InstallSuccess = true; #if !__MonoCS__ // count how many desktop clients IEnumerable <UnrealSessionRole> DesktopClients = SessionRoles.Where(R => R.Platform == BuildHostPlatform.Current.Platform).Where(R => R.RoleType.IsClient()); if (DesktopClients.Count() > 1) { int NumClientRows = (int)Math.Ceiling(DesktopClients.Count() / 2.0); var ScreenRect = System.Windows.Forms.Screen.PrimaryScreen.Bounds; double Ratio = 16.0 / 9.0; // pick width int DesiredWidth = ScreenRect.Width / 2; // height at 16:9 aspect int DesiredHeight = (int)(DesiredWidth / Ratio); // constrain width if the screen can't have that many rows if (DesiredHeight * NumClientRows > ScreenRect.Height) { DesiredHeight = ScreenRect.Height / NumClientRows; DesiredWidth = (int)(DesiredHeight * Ratio); } // now set all these params and disable the regular params that pick windowed stuff for (int i = 0; i < DesktopClients.Count(); i++) { UnrealSessionRole Role = DesktopClients.ElementAt(i); int Row = i / 2; int Column = i - (Row * 2); // this is hacky, but not sure if a better way to do it right now without changing interfaces in a TBD way UnrealTestConfiguration ConfigOptions = Role.Options as UnrealTestConfiguration; if (ConfigOptions != null) { ConfigOptions.IgnoreDefaultResolutionAndWindowMode = true; } Role.CommandLine += string.Format(" -WinX={0} -WinY={1} -ResX={2} -ResY={3} -windowed", Column * DesiredWidth, Row * DesiredHeight, DesiredWidth, DesiredHeight); } } #endif // sort by constraints, so that we pick constrained devices first List <UnrealSessionRole> SortedRoles = SessionRoles.OrderBy(R => R.Constraint.IsIdentity() ? 1 : 0).ToList(); // first install all roles on these devices foreach (var Role in SortedRoles) { ITargetDevice Device = null; if (Role.IsNullRole() == false) { Device = DevicesToInstallOn.Where(D => D.IsConnected && D.Platform == Role.Platform && (Role.Constraint.IsIdentity() || DevicePool.Instance.GetConstraint(D) == Role.Constraint)).First(); DevicesToInstallOn = DevicesToInstallOn.Where(D => D != Device); } else { Device = new TargetDeviceNull(string.Format("Null{0}", Role.RoleType)); } var OtherRoles = SortedRoles.Where(R => R != Role); // create a config from the build source (this also applies the role options) UnrealAppConfig AppConfig = BuildSource.CreateConfiguration(Role, OtherRoles); // todo - should this be elsewhere? AppConfig.Sandbox = Sandbox; IAppInstall Install = null; try { Install = Device.InstallApplication(AppConfig); } catch (System.Exception Ex) { // Warn, ignore the device, and do not continue Log.Info("Failed to install app onto device {0} for role {1}. {2}. Will retry with new device", Device, Role, Ex); MarkProblemDevice(Device); InstallSuccess = false; break; } if (Globals.CancelSignalled) { break; } // Device has app installed, give role a chance to configure device Role.ConfigureDevice?.Invoke(Device); InstallsToRoles[Install] = Role; } if (InstallSuccess == false) { // release all devices ReleaseDevices(); } if (InstallSuccess && Globals.CancelSignalled == false) { List <UnrealSessionInstance.RoleInstance> RunningRoles = new List <UnrealSessionInstance.RoleInstance>(); // Now try to run all installs on their devices foreach (var InstallRoleKV in InstallsToRoles) { IAppInstall CurrentInstall = InstallRoleKV.Key; bool Success = false; try { IAppInstance Instance = CurrentInstall.Run(); if (Instance != null || Globals.CancelSignalled) { RunningRoles.Add(new UnrealSessionInstance.RoleInstance(InstallRoleKV.Value, Instance)); } Success = true; } catch (DeviceException Ex) { // shutdown all Log.Warning("Device {0} threw an exception during launch. \nException={1}", CurrentInstall.Device, Ex.Message); Success = false; } if (Success == false) { Log.Warning("Failed to start build on {0}. Marking as problem device and retrying with new set", CurrentInstall.Device); // terminate anything that's running foreach (UnrealSessionInstance.RoleInstance RunningRole in RunningRoles) { Log.Info("Shutting down {0}", RunningRole.AppInstance.Device); RunningRole.AppInstance.Kill(); RunningRole.AppInstance.Device.Disconnect(); } // mark that device as a problem MarkProblemDevice(CurrentInstall.Device); // release all devices ReleaseDevices(); break; // do not continue loop } } if (RunningRoles.Count() == SessionRoles.Count()) { SessionInstance = new UnrealSessionInstance(RunningRoles.ToArray()); } } } return(SessionInstance); }
public RoleInstance(UnrealSessionRole InRole, IAppInstance InInstance) { Role = InRole; AppInstance = InInstance; }
virtual public UnrealAppConfig CreateConfiguration(UnrealSessionRole Role, IEnumerable <UnrealSessionRole> OtherRoles) { List <string> Issues = new List <string>(); Log.Verbose("Creating configuration Role {0}", Role); if (!CanSupportRole(Role, ref Issues)) { Issues.ForEach(S => Log.Error(S)); return(null); } UnrealAppConfig Config = new UnrealAppConfig(); Config.Name = this.BuildName; Config.ProjectName = ProjectName; Config.ProcessType = Role.RoleType; Config.Platform = Role.Platform; Config.Configuration = Role.Configuration; Config.CommandLine = ""; Config.FilesToCopy = new List <UnrealFileToCopy>(); // new system of retrieving and encapsulating the info needed to install/launch. Android & Mac Config.Build = GetMatchingBuilds(Role.RoleType, Role.Platform, Role.Configuration, Role.RequiredBuildFlags).FirstOrDefault(); if (Config.Build == null && Role.IsNullRole() == false) { var SupportedBuilds = String.Join("\n", DiscoveredBuilds.Select(B => B.ToString())); Log.Info("Available builds:\n{0}", SupportedBuilds); throw new AutomationException("No build found that can support a role of {0}.", Role); } if (Role.Options != null) { UnrealTestConfiguration ConfigOptions = Role.Options as UnrealTestConfiguration; ConfigOptions.ApplyToConfig(Config, Role, OtherRoles); } if (string.IsNullOrEmpty(Role.CommandLine) == false) { Config.CommandLine += " " + Role.CommandLine; } // Cleanup the commandline Config.CommandLine = GenerateProcessedCommandLine(Config.CommandLine); // Now add the project (the above code doesn't handle arguments without a leading - so do this last bool IsContentOnlyProject = (Config.Build.Flags & BuildFlags.ContentOnlyProject) == BuildFlags.ContentOnlyProject; // Add in editor - TODO, should this be in the editor build? if (Role.RoleType.UsesEditor() || IsContentOnlyProject) { // add in -game or -server if (Role.RoleType.IsClient()) { Config.CommandLine = "-game " + Config.CommandLine; } else if (Role.RoleType.IsServer()) { Config.CommandLine = "-server " + Config.CommandLine; } string ProjectParam = ProjectPath.FullName; // if content only we need to provide a relative path to the uproject. if (IsContentOnlyProject && !Role.RoleType.UsesEditor()) { ProjectParam = string.Format("../../../{0}/{0}.uproject", ProjectName); } // project must be first Config.CommandLine = String.Format("\"{0}\"", ProjectParam) + " " + Config.CommandLine; } if (Role.FilesToCopy != null) { Config.FilesToCopy = Role.FilesToCopy; } return(Config); }
virtual public UnrealAppConfig CreateConfiguration(UnrealSessionRole Role) { return(CreateConfiguration(Role, new UnrealSessionRole[] { })); }
protected bool PrepareUnrealApp() { // Get our configuration TConfigClass Config = GetConfiguration(); if (Config == null) { throw new AutomationException("Test {0} returned null config!", this); } if (UnrealApp != null) { throw new AutomationException("Node already has an UnrealApp, was PrepareUnrealSession called twice?"); } // pass through any arguments such as -TestNameArg or -TestNameArg=Value var TestName = this.GetType().Name; var ShortName = TestName.Replace("Test", ""); var PassThroughArgs = Context.TestParams.AllArguments .Where(A => A.StartsWith(TestName, System.StringComparison.OrdinalIgnoreCase) || A.StartsWith(ShortName, System.StringComparison.OrdinalIgnoreCase)) .Select(A => { A = "-" + A; var EqIndex = A.IndexOf("="); // no =? Just a -switch then if (EqIndex == -1) { return(A); } var Cmd = A.Substring(0, EqIndex + 1); var Args = A.Substring(EqIndex + 1); // if no space in the args, just leave it if (Args.IndexOf(" ") == -1) { return(A); } return(string.Format("{0}\"{1}\"", Cmd, Args)); }); List <UnrealSessionRole> SessionRoles = new List <UnrealSessionRole>(); // Go through each type of role that was required and create a session role foreach (var TypesToRoles in Config.RequiredRoles) { // get the actual context of what this role means. UnrealTestRoleContext RoleContext = Context.GetRoleContext(TypesToRoles.Key); foreach (UnrealTestRole TestRole in TypesToRoles.Value) { // important, use the type from the ContextRolke because Server may have been mapped to EditorServer etc UnrealTargetPlatform SessionPlatform = TestRole.PlatformOverride != UnrealTargetPlatform.Unknown ? TestRole.PlatformOverride : RoleContext.Platform; UnrealSessionRole SessionRole = new UnrealSessionRole(RoleContext.Type, SessionPlatform, RoleContext.Configuration, TestRole.CommandLine); SessionRole.RoleModifier = TestRole.RoleType; SessionRole.Constraint = TestRole.Type == UnrealTargetRole.Client ? Context.Constraint : new UnrealTargetConstraint(SessionPlatform); Log.Verbose("Created SessionRole {0} from RoleContext {1} (RoleType={2})", SessionRole, RoleContext, TypesToRoles.Key); // TODO - this can all / mostly go into UnrealTestConfiguration.ApplyToConfig // Deal with command lines if (string.IsNullOrEmpty(TestRole.ExplicitClientCommandLine) == false) { SessionRole.CommandLine = TestRole.ExplicitClientCommandLine; } else { // start with anything from our context SessionRole.CommandLine = RoleContext.ExtraArgs; // did the test ask for anything? if (string.IsNullOrEmpty(TestRole.CommandLine) == false) { SessionRole.CommandLine += " " + TestRole.CommandLine; } // add controllers if (TestRole.Controllers.Count > 0) { SessionRole.CommandLine += string.Format(" -gauntlet=\"{0}\"", string.Join(",", TestRole.Controllers)); } if (PassThroughArgs.Count() > 0) { SessionRole.CommandLine += " " + string.Join(" ", PassThroughArgs); } // add options SessionRole.Options = Config; } if (RoleContext.Skip) { SessionRole.RoleModifier = ERoleModifier.Null; } SessionRole.FilesToCopy = TestRole.FilesToCopy; SessionRoles.Add(SessionRole); } } UnrealApp = new UnrealSession(Context.BuildInfo, SessionRoles) { Sandbox = Context.Options.Sandbox }; return(true); }