示例#1
0
 public void Initialize(
     [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(AddinMarshaler))] IAppInstance
     appInstance)
 {
     _appInstance = appInstance;
     InitializeTaxPrepAddin();
 }
示例#2
0
        public static void InitTestEvents(IAppInstance aAppInstance)
        {
            var lService = (IAppModuleManager)aAppInstance;

            lService.BeforeCurrentModuleChange = new NotifyHandler(aModule => BeforeCurrentModuleChangeCount++);
            lService.AfterCurrentModuleChange  = new NotifyHandler(aModule => AfterCurrentModuleChangeCount++);
        }
示例#3
0
        public static void AddTestMenu(IAppInstance aAppInstance, Assembly aAssemblyWithTests, IAppSubMenu aParentSubMenu, bool aSeparatorBefore)
        {
            var lMenuItem = aParentSubMenu.AddItem("Run Unit Tests", aSeparatorBefore);

            lMenuItem.ClickHandler = new TestHost(aAppInstance, aAssemblyWithTests);
            lMenuItem.Visible      = true;
            lMenuItem.Enabled      = true;
        }
示例#4
0
 /// <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;
 }
        public static void InitTestEvents(IAppInstance aAppInstance)
        {
            var lTaxAppService = (IAppTaxApplicationService)aAppInstance;

            lTaxAppService.OnIdle = new AppIdleHandler((out bool aProcessed) =>
            {
                AppIdleCount++;
                aProcessed = true;
            });
        }
示例#6
0
        /// <summary>
        /// Periodically called while the test is running. A chance for tests to examine their
        /// health, log updates etc. Base classes must call this or take all responsibility for
        /// setting Status as necessary
        /// </summary>
        /// <returns></returns>
        public override void TickTest()
        {
            IAppInstance App = null;

            if (TestInstance.ClientApps == null)
            {
                App = TestInstance.ServerApp;
            }
            else
            {
                if (TestInstance.ClientApps.Length > 0)
                {
                    App = TestInstance.ClientApps.First();
                }
            }

            if (App != null)
            {
                UnrealLogParser Parser = new UnrealLogParser(App.StdOut);

                // TODO - hardcoded for Orion
                List <string> TestLines = Parser.GetLogChannel("Gauntlet").ToList();

                TestLines.AddRange(Parser.GetLogChannel("OrionTest"));

                for (int i = LastLogCount; i < TestLines.Count; i++)
                {
                    Log.Info(TestLines[i]);

                    if (Regex.IsMatch(TestLines[i], @".*GauntletHeartbeat\: Active.*"))
                    {
                        LastHeartbeatTime       = DateTime.Now;
                        LastActiveHeartbeatTime = DateTime.Now;
                    }
                    else if (Regex.IsMatch(TestLines[i], @".*GauntletHeartbeat\: Idle.*"))
                    {
                        LastHeartbeatTime = DateTime.Now;
                    }
                }

                LastLogCount = TestLines.Count;

                // Detect missed heartbeats and fail the test
                CheckHeartbeat();
            }


            // Check status and health after updating logs
            if (GetTestStatus() == TestStatus.InProgress && IsTestRunning() == false)
            {
                MarkTestComplete();
            }
        }
示例#7
0
        private static void GetTaxPrepAppUsingGuid()
        {
            var     helper            = new ComRegistrationHelper();
            var     guidTemplate      = ConfigurationManager.AppSettings["TaxPrepComGuidTemplate"];
            var     taxPrepFileName   = ConfigurationManager.AppSettings["TaxPrepFileName"];
            var     guid              = helper.CreateApplicationSpecificGuidFromTemplate(guidTemplate, taxPrepFileName);
            var     type              = Type.GetTypeFromCLSID(guid, true);
            dynamic comAccessProvider = Activator.CreateInstance(type);

            dynamic appInstance = comAccessProvider.GetAppInstance();

            _appInstance = (IAppInstance)appInstance;
        }
示例#8
0
        public MainForm(IAppInstance app, Func<AnalysisResultsForm> analysisResultsFormFactory,
            Func<AnalyzeWebPageForWordsForm> analyzeWebPageForWordsFormFactory,
            Func<ResolveReplaceAmbiguityForm> resolveAmbiguityFormFactory, IDocumentAnalyzer documentAnalyzer,
            IDocumentProcessor documentProcessor)
        {
            this.app = app;
            this.analysisResultsFormFactory = analysisResultsFormFactory;
            this.analyzeWebPageForWordsFormFactory = analyzeWebPageForWordsFormFactory;
            this.resolveAmbiguityFormFactory = resolveAmbiguityFormFactory;
            this.documentAnalyzer = documentAnalyzer;
            this.documentProcessor = documentProcessor;

            InitializeComponent();
        }
示例#9
0
        public void Init(IAppInstance appInstance)
        {
            _appInstance = appInstance;

            var menuName = string.Format("Sample COM Add-In v{0}", m_version);

            InitMenu(menuName);
            InitClientFileEvents();
            InitCustomDiagnostic();
            InitDatabaseEnvEvents();
            //  InitDragDrop();
            InitModuleManager();
            InitApplicationEvents();
        }
示例#10
0
        protected void TestInstallThenRun(UnrealBuildSource Build, UnrealTargetRole ProcessType, ITargetDevice Device, UnrealTargetConfiguration Config, UnrealOptions InOptions = null)
        {
            // create a config based on the passed in params

            UnrealSessionRole Role = new UnrealSessionRole(ProcessType, Device.Platform, Config, InOptions);

            Log.Info("Testing {0}", Role);

            UnrealAppConfig AppConfig = Build.CreateConfiguration(Role);

            if (!CheckResult(AppConfig != null, "Could not create config for {0} {1} with platform {2} from build.", Config, ProcessType, Device))
            {
                MarkComplete();
                return;
            }

            // Install the app on this device
            IAppInstall AppInstall = Device.InstallApplication(AppConfig);

            CheckResult(AppConfig != null, "Could not create AppInstall for {0} {1} with platform {2} from build.", Config, ProcessType, Device);


            DateTime StartTime = DateTime.Now;

            // Run the app and wait for either a timeout or it to exit
            IAppInstance AppProcess = AppInstall.Run();

            while (AppProcess.HasExited == false)
            {
                if ((DateTime.Now - StartTime).TotalSeconds > 60)
                {
                    break;
                }

                Thread.Sleep(1000);
            }

            // Check it didn't exit unexpectedly
            CheckResult(AppProcess.HasExited == false, "Failed to run {0} {1} with platform {2}", Config, ProcessType, Device);

            // but kill it
            AppProcess.Kill();

            // Check that it left behind some artifacts (minimum should be a log)
            int ArtifactCount = new DirectoryInfo(AppProcess.ArtifactPath).GetFiles("*", SearchOption.AllDirectories).Length;

            CheckResult(ArtifactCount > 0, "No artifacts on device!");
        }
示例#11
0
        public override void TickTest()
        {
            if (TestInstance.ClientApps.Length > 0)
            {
                IAppInstance App = TestInstance.ClientApps.First();

                UnrealLogParser Log = new UnrealLogParser(App.StdOut);

                // Look for message that test is completed
                if (Log.GetAllMatchingLines("FortGPUTestbedPerfTest Finished").Length > 0)
                {
                    MarkTestComplete();
                    SetUnrealTestResult(TestResult.Passed);
                }
            }

            base.TickTest();
        }
        /// <summary>
        /// Called periodically while the test is running to allow code to monitor health.
        /// </summary>
        public override void TickTest()
        {
            const int    kTimeOutDuration       = 2;
            const string kStartupCompleteString = "Bringing up level for play took";

            // run the base class tick;
            base.TickTest();

            // Get the log of the first client app
            IAppInstance RunningInstance = this.TestInstance.ClientApps.First();

            UnrealLogParser LogParser = new UnrealLogParser(RunningInstance.StdOut);

            // count how many lines there are in the log to check progress
            int LogLines = LogParser.Content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Length;

            if (LogLines > LogLinesLastTick)
            {
                LastLogTime = DateTime.Now;
            }
            // Gauntlet will timeout tests based on the -timeout argument, but we have greater insight here so can bail earlier to save
            // tests from idling on the farm needlessly.
            if ((DateTime.Now - LastLogTime).TotalMinutes > kTimeOutDuration)
            {
                Log.Error("No logfile activity observed in last {0} minutes. Ending test", kTimeOutDuration);
                MarkTestComplete();
                SetUnrealTestResult(TestResult.TimedOut);
            }

            // now see if the game has brought the first world up for play
            IEnumerable <string> LogWorldLines = LogParser.GetLogChannel("World");

            if (LogWorldLines.Any(L => L.IndexOf(kStartupCompleteString) >= 0))
            {
                Log.Info("Found world is ready for play. Ending Test");
                MarkTestComplete();
                DidDetectLaunch = true;
                SetUnrealTestResult(TestResult.Passed);
            }
        }
示例#13
0
        /// <summary>
        /// Periodically called while the test is running. A chance for tests to examine their
        /// health, log updates etc. Base classes must call this or take all responsibility for
        /// setting Status as necessary
        /// </summary>
        /// <returns></returns>
        public override void TickTest()
        {
            IAppInstance App = null;

            if (TestInstance.ClientApps == null)
            {
                App = TestInstance.ServerApp;
            }
            else
            {
                if (TestInstance.ClientApps.Length > 0)
                {
                    App = TestInstance.ClientApps.First();
                }
            }

            if (App != null)
            {
                UnrealLogParser Parser = new UnrealLogParser(App.StdOut);

                // TODO - hardcoded for Orion
                List <string> TestLines = Parser.GetLogChannel("Gauntlet").ToList();

                TestLines.AddRange(Parser.GetLogChannel("OrionTest"));

                for (int i = LastLogCount; i < TestLines.Count; i++)
                {
                    Log.Info(TestLines[i]);
                }

                LastLogCount = TestLines.Count;
            }


            // Check status and health after updating logs
            if (GetTestStatus() == TestStatus.InProgress && IsTestRunning() == false)
            {
                MarkTestComplete();
            }
        }
示例#14
0
        /// <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);
        }
示例#15
0
 public void Init()
 {
     AppInstance = TestHost.CurrentInstance.AppInstance;
 }
示例#16
0
 public RoleInstance(UnrealSessionRole InRole, IAppInstance InInstance)
 {
     Role        = InRole;
     AppInstance = InInstance;
 }
示例#17
0
 public void CleanUp()
 {
     AppInstance = null;
 }
示例#18
0
 public TestBase()
 {
     AppInstance = TestApp.Builder(EnvironmentType.Development).Build();
 }
示例#19
0
 public static void AddTestMenu(IAppInstance aAppInstance, IAppSubMenu aParentSubMenu, bool aSeparatorBefore)
 {
     AddTestMenu(aAppInstance, Assembly.GetExecutingAssembly(), aParentSubMenu, aSeparatorBefore);
 }
示例#20
0
 private TestHost(IAppInstance aAppInstance, Assembly aAssemblyWithTests)
 {
     TestAssembly = aAssemblyWithTests;
     AppInstance  = aAppInstance;
 }
        void TestClientPlatform(UnrealTargetPlatform Platform)
        {
            string GameName  = this.ProjectFile.FullName;
            string BuildPath = this.BuildPath;
            string DevKit    = this.DevkitName;

            if (GameName.Equals("OrionGame", StringComparison.OrdinalIgnoreCase) == false)
            {
                Log.Info("Skipping test {0} due to non-Orion project!", this);
                MarkComplete();
                return;
            }

            // create a new build
            UnrealBuildSource Build = new UnrealBuildSource(ProjectFile, this.UnrealPath, UsesSharedBuildType, BuildPath);

            // check it's valid
            if (!CheckResult(Build.BuildCount > 0, "staged build was invalid"))
            {
                MarkComplete();
                return;
            }

            // Create devices to run the client and server
            ITargetDevice ServerDevice = new TargetDeviceWindows("PC Server", Gauntlet.Globals.TempDir);
            ITargetDevice ClientDevice = null;

            if (Platform == UnrealTargetPlatform.PS4)
            {
                //ClientDevice = new TargetDevicePS4(this.PS4Name);
            }
            else
            {
                ClientDevice = new TargetDeviceWindows("PC Client", Gauntlet.Globals.TempDir);
            }

            UnrealAppConfig ServerConfig = Build.CreateConfiguration(new UnrealSessionRole(UnrealTargetRole.Server, ServerDevice.Platform, UnrealTargetConfiguration.Development));
            UnrealAppConfig ClientConfig = Build.CreateConfiguration(new UnrealSessionRole(UnrealTargetRole.Client, ClientDevice.Platform, UnrealTargetConfiguration.Development));

            if (!CheckResult(ServerConfig != null && ServerConfig != null, "Could not create configs!"))
            {
                MarkComplete();
                return;
            }

            ShortSoloOptions Options = new ShortSoloOptions();

            Options.ApplyToConfig(ClientConfig);
            Options.ApplyToConfig(ServerConfig);

            IAppInstall ClientInstall = ClientDevice.InstallApplication(ClientConfig);
            IAppInstall ServerInstall = ServerDevice.InstallApplication(ServerConfig);

            if (!CheckResult(ServerConfig != null && ServerConfig != null, "Could not create configs!"))
            {
                MarkComplete();
                return;
            }

            IAppInstance ClientInstance = ClientInstall.Run();
            IAppInstance ServerInstance = ServerInstall.Run();

            DateTime StartTime        = DateTime.Now;
            bool     RunWasSuccessful = true;

            while (ClientInstance.HasExited == false)
            {
                if ((DateTime.Now - StartTime).TotalSeconds > 800)
                {
                    RunWasSuccessful = false;
                    break;
                }
            }

            ClientInstance.Kill();
            ServerInstance.Kill();

            UnrealLogParser LogParser = new UnrealLogParser(ClientInstance.StdOut);

            UnrealLogParser.CallstackMessage ErrorInfo = LogParser.GetFatalError();
            if (ErrorInfo != null)
            {
                CheckResult(false, "FatalError - {0}", ErrorInfo.Message);
            }

            RunWasSuccessful = LogParser.HasRequestExit();

            CheckResult(RunWasSuccessful, "Failed to run for platform {0}", Platform);
        }
示例#22
0
        /// <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;

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

                    // create a config from the build source (this also applies the role options)
                    UnrealAppConfig AppConfig = BuildSource.CreateConfiguration(Role);

                    // 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;
                    }

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