public void SetUp() { _targetPath = "/any/old/target/path"; var fileSystem = new MockFileSystem(); fileSystem.AddFile(_targetPath, new MockFileData("")); _outputDirectory = Path.GetTempPath(); _project = Substitute.For <IAsyncProject>(); _project.GetTargetPathAsync().Returns(_targetPath); _project.GetTargetDirectoryAsync().Returns(Path.GetDirectoryName(_targetPath)); _project.GetTargetFileNameAsync().Returns(Path.GetFileName(_targetPath)); _project.GetOutputDirectoryAsync().Returns(_outputDirectory); _project.GetAbsoluteRootPathAsync().Returns(_testProjectDir); _project.GetApplicationAsync().Returns(_testApplicationName); _project.GetQueryParamsAsync().Returns(_customQueryParams); var sdkConfigFactory = Substitute.For <SdkConfig.Factory>(); var sdkConfig = new SdkConfig(); sdkConfig.OrganizationId = _testOrganizationId; sdkConfig.ProjectId = _testProjectId; sdkConfigFactory.LoadOrDefault().Returns(sdkConfig); _gameletClient = Substitute.For <IGameletClient>(); var gameletClientFactory = Substitute.For <GameletClient.Factory>(); gameletClientFactory.Create(Arg.Any <ICloudRunner>()).Returns(_gameletClient); var remoteCommand = Substitute.For <IRemoteCommand>(); _remoteDeploy = Substitute.For <IRemoteDeploy>(); _dialogUtil = Substitute.For <IDialogUtil>(); var credentialManager = Substitute.For <YetiCommon.ICredentialManager>(); credentialManager.LoadAccount().Returns(_testAccount); var cancelableTaskFactory = FakeCancelableTask.CreateFactory(new JoinableTaskContext(), false); _applicationClient = Substitute.For <IApplicationClient>(); var application = new Application { Id = _testApplicationId, Name = _testApplicationName }; _applicationClient.LoadByNameOrIdAsync(_testApplicationName) .Returns(Task.FromResult(application)); var applicationClientFactory = Substitute.For <ApplicationClient.Factory>(); applicationClientFactory.Create(Arg.Any <ICloudRunner>()).Returns(_applicationClient); _testAccountClientFactory = Substitute.For <TestAccountClient.Factory>(); var testAccount = new TestAccount() { Name = $"organizations/{_testOrganizationId}" + $"/projects/{_testProjectId}/testAccounts/{_testTestAccountId}" }; var testAccountClient = Substitute.For <ITestAccountClient>(); testAccountClient .LoadByIdOrGamerTagAsync(_testOrganizationId, _testProjectId, _testTestAccountId) .Returns(new List <TestAccount> { testAccount }); _testAccountClientFactory.Create(Arg.Any <ICloudRunner>()).Returns(testAccountClient); Substitute.For <IExtensionOptions>(); _yetiVsiService = Substitute.For <IYetiVSIService>(); var options = Substitute.For <IExtensionOptions>(); var debuggerOptions = new YetiVSI.DebuggerOptions.DebuggerOptions(); _yetiVsiService.DebuggerOptions.Returns(debuggerOptions); options.LaunchGameApiFlow.Returns(LaunchGameApiFlow.DISABLED); _yetiVsiService.Options.Returns(options); _metrics = Substitute.For <IMetrics>(); _metrics.NewDebugSessionId().Returns(_testDebugSessionId); var debugMetrics = new DebugSessionMetrics(_metrics); var cloudRunner = new CloudRunner(sdkConfigFactory, credentialManager, new CloudConnection(), new GgpSDKUtil()); _gameletSelector = Substitute.For <IGameletSelector>(); _gameletSelectorFactory = Substitute.For <IGameletSelectorFactory>(); _gameletSelectorFactory.Create(Arg.Any <bool>(), Arg.Any <ActionRecorder>()) .Returns(_gameletSelector); var serializer = new JsonUtil(); _launchCommandFormatter = new ChromeClientLaunchCommandFormatter(serializer); _paramsFactory = new YetiVSI.DebugEngine.DebugEngine.Params.Factory(serializer); _gameLauncher = Substitute.For <IGameLauncher>(); _gameLauncher.LaunchGameApiEnabled.Returns(false); _gameLaunch = Substitute.For <IVsiGameLaunch>(); _gameLaunch.LaunchName.Returns("launch_name"); _ggpDebugQueryTarget = new GgpDebugQueryTarget(fileSystem, sdkConfigFactory, gameletClientFactory, applicationClientFactory, cancelableTaskFactory, _dialogUtil, _remoteDeploy, debugMetrics, credentialManager, _testAccountClientFactory, _gameletSelectorFactory, cloudRunner, _sdkVersion, _launchCommandFormatter, _paramsFactory, _yetiVsiService, _gameLauncher); }
public async Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync( IAsyncProject project, DebugLaunchOptions launchOptions) { try { // Make sure we can find the target executable. var targetPath = await project.GetTargetPathAsync(); if (!_fileSystem.File.Exists(targetPath)) { Trace.WriteLine($"Unable to find target executable: {targetPath}"); _dialogUtil.ShowError(ErrorStrings.UnableToFindTargetExecutable(targetPath)); return(new IDebugLaunchSettings[] { }); } _metrics.UseNewDebugSessionId(); var actionRecorder = new ActionRecorder(_metrics); var targetFileName = await project.GetTargetFileNameAsync(); var gameletCommand = (targetFileName + " " + await project.GetGameletLaunchArgumentsAsync()).Trim(); var launchParams = new LaunchParams() { Cmd = gameletCommand, RenderDoc = await project.GetLaunchRenderDocAsync(), Rgp = await project.GetLaunchRgpAsync(), SurfaceEnforcementMode = await project.GetSurfaceEnforcementAsync(), VulkanDriverVariant = await project.GetVulkanDriverVariantAsync(), QueryParams = await project.GetQueryParamsAsync(), Endpoint = await project.GetEndpointAsync() }; if (_sdkVersion != null && !string.IsNullOrEmpty(_sdkVersion.ToString())) { launchParams.SdkVersion = _sdkVersion.ToString(); } if (!TrySetupQueries(project, actionRecorder, out SetupQueriesResult setupQueriesResult)) { return(new IDebugLaunchSettings[] { }); } launchParams.ApplicationName = setupQueriesResult.Application.Name; launchParams.ApplicationId = setupQueriesResult.Application.Id; if (setupQueriesResult.TestAccount != null) { launchParams.TestAccount = setupQueriesResult.TestAccount.Name; launchParams.TestAccountGamerName = setupQueriesResult.TestAccount.GamerStadiaName; } DeployOnLaunchSetting deployOnLaunchAsync = await project.GetDeployOnLaunchAsync(); launchParams.Account = _credentialManager.LoadAccount(); // TODO: Enable PlayerEndpoint Launches for non-internal usage in VS. if (launchParams.Endpoint == StadiaEndpoint.PlayerEndpoint && launchParams.Account != null && !launchParams.Account.EndsWith("@sparklingsunset.com") && !launchParams.Account.EndsWith("@subtlesunset.com")) { throw new NotImplementedException( "Player Endpoints are not yet supported, please select " + "Test Client in the Project Properties instead."); } // TODO: Enable launch on any endpoint for external accounts. if (launchParams.Endpoint == StadiaEndpoint.AnyEndpoint && launchParams.Account != null && !launchParams.Account.EndsWith("@sparklingsunset.com") && !launchParams.Account.EndsWith("@subtlesunset.com")) { throw new NotImplementedException( "Launch on any player endpoint is not supported yet, please select " + "another endpoint in the Project Properties instead."); } bool launchGameApiEnabled = _yetiVsiService.Options.LaunchGameApiFlow == LaunchGameApiFlow.ENABLED; IGameletSelector gameletSelector = _gameletSelectorFactory.Create(launchGameApiEnabled, actionRecorder); if (!gameletSelector.TrySelectAndPrepareGamelet( targetPath, deployOnLaunchAsync, setupQueriesResult.Gamelets, setupQueriesResult.TestAccount, launchParams.Account, out Gamelet gamelet)) { return(new IDebugLaunchSettings[] { }); } launchParams.GameletName = gamelet.Name; launchParams.PoolId = gamelet.PoolId; launchParams.GameletSdkVersion = gamelet.GameletVersions.DevToolingVersion; launchParams.GameletEnvironmentVars = await project.GetGameletEnvironmentVariablesAsync(); // Prepare for debug launch using these settings. var debugLaunchSettings = new DebugLaunchSettings(launchOptions); debugLaunchSettings.Environment["PATH"] = await project.GetExecutablePathAsync(); debugLaunchSettings.LaunchOperation = DebugLaunchOperation.CreateProcess; debugLaunchSettings.CurrentDirectory = await project.GetAbsoluteRootPathAsync(); if (!launchOptions.HasFlag(DebugLaunchOptions.NoDebug)) { var parameters = _paramsFactory.Create(); parameters.TargetIp = new SshTarget(gamelet).GetString(); parameters.DebugSessionId = _metrics.DebugSessionId; debugLaunchSettings.Options = _paramsFactory.Serialize(parameters); } IAction action = actionRecorder.CreateToolAction(ActionType.RemoteDeploy); bool isDeployed = _cancelableTaskFactory.Create( TaskMessages.DeployingExecutable, async task => { await _remoteDeploy.DeployGameExecutableAsync( project, new SshTarget(gamelet), task, action); task.Progress.Report(TaskMessages.CustomDeployCommand); await _remoteDeploy.ExecuteCustomCommandAsync(project, gamelet, action); }).RunAndRecord(action); if (!isDeployed) { return(new IDebugLaunchSettings[] { }); } if (launchOptions.HasFlag(DebugLaunchOptions.NoDebug)) { if (_gameLauncher.LaunchGameApiEnabled || launchParams.Endpoint == StadiaEndpoint.PlayerEndpoint || launchParams.Endpoint == StadiaEndpoint.AnyEndpoint) { IVsiGameLaunch launch = _gameLauncher.CreateLaunch(launchParams); if (launch != null) { debugLaunchSettings.Arguments = _launchCommandFormatter.CreateWithLaunchName( launchParams, launch.LaunchName); } else { Trace.WriteLine("Unable to retrieve launch name from the launch api."); return(new IDebugLaunchSettings[] { }); } } else { debugLaunchSettings.Arguments = _launchCommandFormatter.CreateFromParams(launchParams); } debugLaunchSettings.Executable = Path.Combine(Environment.SystemDirectory, YetiConstants.Command); debugLaunchSettings.LaunchOptions = DebugLaunchOptions.NoDebug | DebugLaunchOptions.MergeEnvironment; } else { if (_yetiVsiService.DebuggerOptions[DebuggerOption.SKIP_WAIT_LAUNCH] == DebuggerOptionState.DISABLED) { launchParams.Debug = true; } // TODO: This should really be the game_client executable, since // the args we pass are for game_client as well. We just need to find another // way to pass the game executable. debugLaunchSettings.Executable = targetPath; debugLaunchSettings.LaunchDebugEngineGuid = YetiConstants.DebugEngineGuid; debugLaunchSettings.Arguments = _launchCommandFormatter.EncodeLaunchParams(launchParams); debugLaunchSettings.LaunchOptions = DebugLaunchOptions.MergeEnvironment; } return(new IDebugLaunchSettings[] { debugLaunchSettings }); } catch (Exception e) { Trace.WriteLine(e.ToString()); _dialogUtil.ShowError(e.Message, e.ToString()); return(new IDebugLaunchSettings[] { }); } }