[platform] mock update server
[idea/community.git] / python / testSrc / com / jetbrains / env / python / debug / PyDebuggerTask.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.jetbrains.env.python.debug;
17
18 import com.intellij.execution.*;
19 import com.intellij.execution.configurations.ConfigurationFactory;
20 import com.intellij.execution.configurations.RunProfile;
21 import com.intellij.execution.executors.DefaultDebugExecutor;
22 import com.intellij.execution.process.KillableColoredProcessHandler;
23 import com.intellij.execution.process.ProcessAdapter;
24 import com.intellij.execution.process.ProcessEvent;
25 import com.intellij.execution.process.ProcessHandler;
26 import com.intellij.execution.runners.ExecutionEnvironment;
27 import com.intellij.openapi.application.Result;
28 import com.intellij.openapi.application.WriteAction;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.xdebugger.*;
31 import com.jetbrains.env.python.PythonDebuggerTest;
32 import com.jetbrains.python.debugger.PyDebugProcess;
33 import com.jetbrains.python.debugger.PyDebugRunner;
34 import com.jetbrains.python.run.PythonCommandLineState;
35 import com.jetbrains.python.run.PythonConfigurationType;
36 import com.jetbrains.python.run.PythonRunConfiguration;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
39 import org.junit.Assert;
40
41 import java.io.IOException;
42 import java.net.ServerSocket;
43 import java.util.concurrent.Semaphore;
44
45 /**
46  * @author traff
47  */
48 public class PyDebuggerTask extends PyBaseDebuggerTask {
49
50   private boolean myMultiprocessDebug = false;
51   private PythonRunConfiguration myRunConfiguration;
52
53
54   public PyDebuggerTask(@Nullable final String relativeTestDataPath, String scriptName, String scriptParameters) {
55     super(relativeTestDataPath);
56     setScriptName(scriptName);
57     setScriptParameters(scriptParameters);
58     init();
59   }
60
61   public PyDebuggerTask(@Nullable final String relativeTestDataPath, String scriptName) {
62     this(relativeTestDataPath, scriptName, null);
63   }
64
65   protected void init() {
66
67   }
68
69   public void runTestOn(String sdkHome) throws Exception {
70     final Project project = getProject();
71
72     final ConfigurationFactory factory = PythonConfigurationType.getInstance().getConfigurationFactories()[0];
73
74
75     final RunnerAndConfigurationSettings settings =
76       RunManager.getInstance(project).createRunConfiguration("test", factory);
77
78     myRunConfiguration = (PythonRunConfiguration)settings.getConfiguration();
79
80     myRunConfiguration.setSdkHome(sdkHome);
81     myRunConfiguration.setScriptName(getScriptName());
82     myRunConfiguration.setWorkingDirectory(myFixture.getTempDirPath());
83     myRunConfiguration.setScriptParameters(getScriptParameters());
84
85     new WriteAction() {
86       @Override
87       protected void run(@NotNull Result result) throws Throwable {
88         RunManagerEx.getInstanceEx(project).addConfiguration(settings, false);
89         RunManagerEx.getInstanceEx(project).setSelectedConfiguration(settings);
90         Assert.assertSame(settings, RunManagerEx.getInstanceEx(project).getSelectedConfiguration());
91       }
92     }.execute();
93
94     final PyDebugRunner runner = (PyDebugRunner)ProgramRunnerUtil.getRunner(getExecutorId(), settings);
95     Assert.assertTrue(runner.canRun(getExecutorId(), myRunConfiguration));
96
97     final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance();
98     final ExecutionEnvironment env = new ExecutionEnvironment(executor, runner, settings, project);
99
100     final PythonCommandLineState pyState = (PythonCommandLineState)myRunConfiguration.getState(executor, env);
101
102     assert pyState != null;
103     pyState.setMultiprocessDebug(isMultiprocessDebug());
104
105     final ServerSocket serverSocket;
106     try {
107       //noinspection SocketOpenedButNotSafelyClosed
108       serverSocket = new ServerSocket(0);
109     }
110     catch (IOException e) {
111       throw new ExecutionException("Failed to find free socket port", e);
112     }
113
114
115     final int serverLocalPort = serverSocket.getLocalPort();
116     final RunProfile profile = env.getRunProfile();
117
118     PythonDebuggerTest.createExceptionBreak(myFixture, false, false, false); //turn off exception breakpoints by default
119
120     before();
121
122     setProcessCanTerminate(false);
123
124     myTerminateSemaphore = new Semaphore(0);
125     
126     new WriteAction<ExecutionResult>() {
127       @Override
128       protected void run(@NotNull Result<ExecutionResult> result) throws Throwable {
129         myExecutionResult =
130           pyState.execute(executor, runner.createCommandLinePatchers(myFixture.getProject(), pyState, profile, serverLocalPort));
131
132         mySession = XDebuggerManager.getInstance(getProject()).
133           startSession(env, new XDebugProcessStarter() {
134             @NotNull
135             public XDebugProcess start(@NotNull final XDebugSession session) {
136               myDebugProcess =
137                 new PyDebugProcess(session, serverSocket, myExecutionResult.getExecutionConsole(), myExecutionResult.getProcessHandler(), isMultiprocessDebug());
138
139               myDebugProcess.getProcessHandler().addProcessListener(new ProcessAdapter() {
140
141                 @Override
142                 public void processTerminated(ProcessEvent event) {
143                   myTerminateSemaphore.release();
144                   if (event.getExitCode() != 0 && !myProcessCanTerminate) {
145                     Assert.fail("Process terminated unexpectedly\n" + output());
146                   }
147                 }
148               });
149
150
151               myDebugProcess.getProcessHandler().startNotify();
152
153               return myDebugProcess;
154             }
155           });
156         result.setResult(myExecutionResult);
157       }
158     }.execute().getResultObject();
159
160     OutputPrinter myOutputPrinter = null;
161     if (shouldPrintOutput) {
162       myOutputPrinter = new OutputPrinter();
163       myOutputPrinter.start();
164     }
165
166
167     myPausedSemaphore = new Semaphore(0);
168     
169
170     mySession.addSessionListener(new XDebugSessionAdapter() {
171       @Override
172       public void sessionPaused() {
173         if (myPausedSemaphore != null) {
174           myPausedSemaphore.release();
175         }
176       }
177     });
178
179     doTest(myOutputPrinter);
180   }
181
182   protected String getExecutorId() {
183     return DefaultDebugExecutor.EXECUTOR_ID;
184   }
185
186   public PythonRunConfiguration getRunConfiguration() {
187     return myRunConfiguration;
188   }
189
190   private boolean isMultiprocessDebug() {
191     return myMultiprocessDebug;
192   }
193
194   public void setMultiprocessDebug(boolean multiprocessDebug) {
195     myMultiprocessDebug = multiprocessDebug;
196   }
197
198   @Override
199   protected void disposeDebugProcess() throws InterruptedException {
200     if (myDebugProcess != null) {
201       ProcessHandler processHandler = myDebugProcess.getProcessHandler();
202
203       myDebugProcess.stop();
204
205       waitFor(processHandler);
206
207       if (!processHandler.isProcessTerminated()) {
208         killDebugProcess();
209         if (!waitFor(processHandler)) {
210           new Throwable("Cannot stop debugger process").printStackTrace();
211         }
212       }
213     }
214   }
215
216   private void killDebugProcess() {
217     if (myDebugProcess.getProcessHandler() instanceof KillableColoredProcessHandler) {
218       KillableColoredProcessHandler h = (KillableColoredProcessHandler)myDebugProcess.getProcessHandler();
219
220       h.killProcess();
221     }
222     else {
223       myDebugProcess.getProcessHandler().destroyProcess();
224     }
225   }
226 }