fixed testDebuggerStop
[idea/community.git] / java / testFramework / src / com / intellij / debugger / DebuggerTestCase.java
1 /*
2  * Copyright 2000-2016 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.intellij.debugger;
17
18 import com.intellij.JavaTestUtil;
19 import com.intellij.debugger.engine.DebugProcessImpl;
20 import com.intellij.debugger.engine.JavaDebugProcess;
21 import com.intellij.debugger.engine.RemoteStateState;
22 import com.intellij.debugger.engine.SuspendContextImpl;
23 import com.intellij.debugger.engine.evaluation.EvaluateException;
24 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
25 import com.intellij.debugger.engine.events.DebuggerCommandImpl;
26 import com.intellij.debugger.impl.*;
27 import com.intellij.debugger.jdi.StackFrameProxyImpl;
28 import com.intellij.debugger.settings.DebuggerSettings;
29 import com.intellij.debugger.settings.NodeRendererSettings;
30 import com.intellij.debugger.ui.breakpoints.BreakpointManager;
31 import com.intellij.execution.ExecutionException;
32 import com.intellij.execution.Executor;
33 import com.intellij.execution.configurations.*;
34 import com.intellij.execution.executors.DefaultDebugExecutor;
35 import com.intellij.execution.process.ProcessAdapter;
36 import com.intellij.execution.process.ProcessEvent;
37 import com.intellij.execution.process.ProcessHandler;
38 import com.intellij.execution.process.ProcessOutputTypes;
39 import com.intellij.execution.runners.ExecutionEnvironment;
40 import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
41 import com.intellij.execution.runners.ProgramRunner;
42 import com.intellij.openapi.application.ApplicationManager;
43 import com.intellij.openapi.application.ModalityState;
44 import com.intellij.openapi.editor.Document;
45 import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
46 import com.intellij.openapi.module.Module;
47 import com.intellij.openapi.options.SettingsEditor;
48 import com.intellij.openapi.project.Project;
49 import com.intellij.openapi.util.Computable;
50 import com.intellij.openapi.util.InvalidDataException;
51 import com.intellij.openapi.util.Key;
52 import com.intellij.openapi.util.WriteExternalException;
53 import com.intellij.openapi.util.text.StringUtil;
54 import com.intellij.psi.JavaPsiFacade;
55 import com.intellij.psi.PsiClass;
56 import com.intellij.psi.PsiDocumentManager;
57 import com.intellij.psi.PsiFile;
58 import com.intellij.psi.search.GlobalSearchScope;
59 import com.intellij.util.ui.UIUtil;
60 import com.intellij.xdebugger.XDebugProcess;
61 import com.intellij.xdebugger.XDebugProcessStarter;
62 import com.intellij.xdebugger.XDebugSession;
63 import com.intellij.xdebugger.XDebuggerManager;
64 import com.sun.jdi.Location;
65 import org.jdom.Element;
66 import org.jetbrains.annotations.NotNull;
67
68 import javax.swing.*;
69 import java.lang.reflect.InvocationTargetException;
70 import java.util.StringTokenizer;
71
72 public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCase {
73   public static final int DEFAULT_ADDRESS = 3456;
74   protected DebuggerSession myDebuggerSession;
75
76   @Override
77   protected void initApplication() throws Exception {
78     super.initApplication();
79     JavaTestUtil.setupTestJDK();
80     DebuggerSettings.getInstance().DEBUGGER_TRANSPORT = DebuggerSettings.SOCKET_TRANSPORT;
81     DebuggerSettings.getInstance().SKIP_CONSTRUCTORS = false;
82     DebuggerSettings.getInstance().SKIP_GETTERS      = false;
83     NodeRendererSettings.getInstance().getClassRenderer().SHOW_DECLARED_TYPE = true;
84   }
85
86   @Override
87   protected void runTest() throws Throwable {
88     super.runTest();
89     if(getDebugProcess() != null) {
90       getDebugProcess().getProcessHandler().startNotify();
91       waitProcess(getDebugProcess().getProcessHandler());
92       waitForCompleted();
93       //disposeSession(myDebuggerSession);
94       assertNull(DebuggerManagerEx.getInstanceEx(myProject).getDebugProcess(getDebugProcess().getProcessHandler()));
95       myDebuggerSession = null;
96     }
97     throwExceptionsIfAny();
98     checkTestOutput();
99   }
100
101   protected void checkTestOutput() throws Exception {
102     getChecker().checkValid(getTestProjectJdk());
103   }
104
105   protected void disposeSession(final DebuggerSession debuggerSession) throws InterruptedException, InvocationTargetException {
106     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
107       @Override
108       public void run() {
109         debuggerSession.dispose();
110       }
111     });
112   }
113
114   @Override
115   protected void tearDown() throws Exception {
116     try {
117       FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
118       if (myDebugProcess != null) {
119         myDebugProcess.stop(true);
120         myDebugProcess.waitFor();
121       }
122     }
123     finally {
124       super.tearDown();
125     }
126   }
127
128   protected void createLocalProcess(String className) throws ExecutionException, InterruptedException, InvocationTargetException {
129     LOG.assertTrue(myDebugProcess == null);
130     myDebuggerSession = createLocalProcess(DebuggerSettings.SOCKET_TRANSPORT, createJavaParameters(className));
131     myDebugProcess = myDebuggerSession.getProcess();
132   }
133
134   protected DebuggerSession createLocalSession(final JavaParameters javaParameters) throws ExecutionException, InterruptedException {
135     createBreakpoints(javaParameters.getMainClass());
136     DebuggerSettings.getInstance().DEBUGGER_TRANSPORT = DebuggerSettings.SOCKET_TRANSPORT;
137
138     GenericDebuggerRunnerSettings debuggerRunnerSettings = new GenericDebuggerRunnerSettings();
139     debuggerRunnerSettings.LOCAL = true;
140
141     final RemoteConnection debugParameters = DebuggerManagerImpl.createDebugParameters(javaParameters, debuggerRunnerSettings, false);
142
143     ExecutionEnvironment environment = new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance())
144       .runnerSettings(debuggerRunnerSettings)
145       .runProfile(new MockConfiguration())
146       .build();
147     final JavaCommandLineState javaCommandLineState = new JavaCommandLineState(environment){
148       @Override
149       protected JavaParameters createJavaParameters() {
150         return javaParameters;
151       }
152
153       @Override
154       protected GeneralCommandLine createCommandLine() throws ExecutionException {
155         return CommandLineBuilder.createFromJavaParameters(getJavaParameters());
156       }
157     };
158
159     ApplicationManager.getApplication().invokeAndWait(new Runnable() {
160       @Override
161       public void run() {
162         try {
163           myDebuggerSession =
164             DebuggerManagerEx.getInstanceEx(myProject)
165               .attachVirtualMachine(new DefaultDebugEnvironment(new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance())
166                                                                   .runProfile(new MockConfiguration())
167                                                                   .build(), javaCommandLineState, debugParameters, false));
168           XDebuggerManager.getInstance(myProject).startSession(javaCommandLineState.getEnvironment(), new XDebugProcessStarter() {
169             @Override
170             @NotNull
171             public XDebugProcess start(@NotNull XDebugSession session) {
172               return JavaDebugProcess.create(session, myDebuggerSession);
173             }
174           });
175         }
176         catch (ExecutionException e) {
177           LOG.error(e);
178         }
179       }
180     }, ModalityState.defaultModalityState());
181     myDebugProcess = myDebuggerSession.getProcess();
182
183     myDebugProcess.addProcessListener(new ProcessAdapter() {
184       @Override
185       public void onTextAvailable(ProcessEvent event, Key outputType) {
186         print(event.getText(), outputType);
187       }
188     });
189
190     assertNotNull(myDebuggerSession);
191     assertNotNull(myDebugProcess);
192
193     return myDebuggerSession;
194   }
195
196
197   protected DebuggerSession createLocalProcess(int transport, final JavaParameters javaParameters) throws ExecutionException, InterruptedException, InvocationTargetException {
198     createBreakpoints(javaParameters.getMainClass());
199     final DebuggerSession[] debuggerSession = new DebuggerSession[]{null};
200
201     DebuggerSettings.getInstance().DEBUGGER_TRANSPORT = transport;
202
203     GenericDebuggerRunnerSettings debuggerRunnerSettings = new GenericDebuggerRunnerSettings();
204     debuggerRunnerSettings.LOCAL = true;
205     debuggerRunnerSettings.setDebugPort(String.valueOf(DEFAULT_ADDRESS));
206
207     ExecutionEnvironment environment = new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance())
208       .runnerSettings(debuggerRunnerSettings)
209       .runProfile(new MockConfiguration())
210       .build();
211     final JavaCommandLineState javaCommandLineState = new JavaCommandLineState(environment) {
212       @Override
213       protected JavaParameters createJavaParameters() {
214         return javaParameters;
215       }
216
217       @Override
218       protected GeneralCommandLine createCommandLine() throws ExecutionException {
219         return CommandLineBuilder.createFromJavaParameters(getJavaParameters());
220       }
221     };
222
223     final RemoteConnection debugParameters =
224       DebuggerManagerImpl.createDebugParameters(javaCommandLineState.getJavaParameters(), debuggerRunnerSettings, true);
225
226     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
227       @Override
228       public void run() {
229         try {
230           debuggerSession[0] = attachVirtualMachine(javaCommandLineState, javaCommandLineState.getEnvironment(), debugParameters, false);
231         }
232         catch (ExecutionException e) {
233           fail(e.getMessage());
234         }
235       }
236     });
237
238     final ProcessHandler processHandler = debuggerSession[0].getProcess().getProcessHandler();
239     debuggerSession[0].getProcess().addProcessListener(new ProcessAdapter() {
240       @Override
241       public void onTextAvailable(ProcessEvent event, Key outputType) {
242         print(event.getText(), outputType);
243       }
244     });
245
246     DebugProcessImpl process =
247       (DebugProcessImpl)DebuggerManagerEx.getInstanceEx(myProject).getDebugProcess(processHandler);
248     assertNotNull(process);
249     return debuggerSession[0];
250   }
251
252
253   protected DebuggerSession createRemoteProcess(final int transport, final boolean serverMode, JavaParameters javaParameters)
254           throws ExecutionException, InterruptedException, InvocationTargetException {
255     boolean useSockets = transport == DebuggerSettings.SOCKET_TRANSPORT;
256
257     RemoteConnection remoteConnection = new RemoteConnection(
258       useSockets,
259       "127.0.0.1",
260       String.valueOf(DEFAULT_ADDRESS),
261       serverMode);
262
263     String launchCommandLine = remoteConnection.getLaunchCommandLine();
264
265     launchCommandLine = StringUtil.replace(launchCommandLine,  RemoteConnection.ONTHROW, "");
266     launchCommandLine = StringUtil.replace(launchCommandLine,  RemoteConnection.ONUNCAUGHT, "");
267
268     launchCommandLine = StringUtil.replace(launchCommandLine, "suspend=n", "suspend=y");
269
270     println(launchCommandLine, ProcessOutputTypes.SYSTEM);
271
272     for(StringTokenizer tokenizer = new StringTokenizer(launchCommandLine);tokenizer.hasMoreTokens();) {
273       String token = tokenizer.nextToken();
274       javaParameters.getVMParametersList().add(token);
275     }
276
277     GeneralCommandLine commandLine = CommandLineBuilder.createFromJavaParameters(javaParameters);
278
279
280     DebuggerSession debuggerSession;
281
282     if(serverMode) {
283       debuggerSession = attachVM(remoteConnection, false);
284       commandLine.createProcess();
285     } else {
286       commandLine.createProcess();
287       debuggerSession = attachVM(remoteConnection, true);
288     }
289
290     ProcessHandler processHandler = debuggerSession.getProcess().getProcessHandler();
291     DebugProcessImpl process = (DebugProcessImpl)DebuggerManagerEx.getInstanceEx(myProject)
292       .getDebugProcess(processHandler);
293
294     assertNotNull(process);
295     return debuggerSession;
296   }
297
298   protected DebuggerSession attachVM(final RemoteConnection remoteConnection, final boolean pollConnection)
299           throws InvocationTargetException, InterruptedException {
300     final RemoteState remoteState = new RemoteStateState(myProject, remoteConnection);
301
302     final DebuggerSession[] debuggerSession = new DebuggerSession[1];
303     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
304       @Override
305       public void run() {
306         try {
307           debuggerSession[0] = attachVirtualMachine(remoteState, new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance())
308             .runProfile(new MockConfiguration())
309             .build(), remoteConnection, pollConnection);
310         }
311         catch (ExecutionException e) {
312           fail(e.getMessage());
313         }
314       }
315     });
316     debuggerSession[0].getProcess().getProcessHandler().addProcessListener(new ProcessAdapter() {
317       @Override
318       public void onTextAvailable(ProcessEvent event, Key outputType) {
319         print(event.getText(), outputType);
320       }
321     });
322     return debuggerSession[0];
323   }
324
325   protected void createBreakpoints(final String className) {
326     final PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
327       @Override
328       public PsiFile compute() {
329         PsiClass psiClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.allScope(myProject));
330         assertNotNull(psiClass);
331         return psiClass.getContainingFile();
332       }
333     });
334
335     createBreakpoints(psiFile);
336   }
337
338   protected EvaluationContextImpl createEvaluationContext(final SuspendContextImpl suspendContext) {
339     try {
340       StackFrameProxyImpl proxy = suspendContext.getFrameProxy();
341       assertNotNull(proxy);
342       return new EvaluationContextImpl(suspendContext, proxy, proxy.thisObject());
343     }
344     catch (EvaluateException e) {
345       error(e);
346       return null;
347     }
348   }
349
350   protected void waitForCompleted() {
351     final SynchronizationBasedSemaphore s = new SynchronizationBasedSemaphore();
352     s.down();
353
354     final InvokeThread.WorkerThreadRequest request = getDebugProcess().getManagerThread().getCurrentRequest();
355     final Thread thread = new Thread("Joining "+request) {
356       @Override
357       public void run() {
358         try {
359           request.join();
360         }
361         catch (Exception ignored) {
362         }
363       }
364     };
365     thread.start();
366     if(request.isDone()) {
367       thread.interrupt();
368     }
369       waitFor(new Runnable() {
370         @Override
371         public void run() {
372           try {
373             thread.join();
374           }
375           catch (InterruptedException ignored) {
376           }
377         }
378       });
379
380     invokeRatherLater(new DebuggerCommandImpl() {
381       @Override
382       protected void action() throws Exception {
383         LOG.assertTrue(false);
384       }
385
386       @Override
387       protected void commandCancelled() {
388         //We wait for invokeRatherLater's
389         invokeRatherLater(new DebuggerCommandImpl() {
390           @Override
391           protected void action() throws Exception {
392             LOG.assertTrue(false);
393           }
394
395           @Override
396           protected void commandCancelled() {
397             s.up();
398           }
399         });
400       }
401     });
402
403     waitFor(new Runnable() {
404       @Override
405       public void run() {
406         s.waitFor();
407       }
408     });
409   }
410
411   public DebuggerContextImpl createDebuggerContext(final SuspendContextImpl suspendContext, StackFrameProxyImpl stackFrame) {
412     final DebuggerSession[] session = new DebuggerSession[1];
413
414     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
415       @Override
416       public void run() {
417         session[0] = DebuggerManagerEx.getInstanceEx(myProject).getSession(suspendContext.getDebugProcess());
418       }
419     });
420
421     DebuggerContextImpl debuggerContext = DebuggerContextImpl.createDebuggerContext(
422             session[0],
423             suspendContext,
424             stackFrame != null ? stackFrame.threadProxy() : null,
425             stackFrame);
426     debuggerContext.initCaches();
427     return debuggerContext;
428   }
429
430   public DebuggerContextImpl createDebuggerContext(final SuspendContextImpl suspendContext) {
431     return createDebuggerContext(suspendContext, suspendContext.getFrameProxy());
432   }
433
434   protected void printLocation(SuspendContextImpl suspendContext) {
435     try {
436       Location location = suspendContext.getFrameProxy().location();
437       String message = "paused at " + location.sourceName() + ":" + location.lineNumber();
438       println(message, ProcessOutputTypes.SYSTEM);
439     }
440     catch (Throwable e) {
441       addException(e);
442     }
443   }
444
445   protected void createBreakpointInHelloWorld() {
446     DebuggerInvocationUtil.invokeAndWait(myProject, new Runnable() {
447       @Override
448       public void run() {
449         BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
450         PsiClass psiClass = JavaPsiFacade.getInstance(myProject).findClass("HelloWorld", GlobalSearchScope.allScope(myProject));
451         assertNotNull(psiClass);
452         Document document = PsiDocumentManager.getInstance(myProject).getDocument(psiClass.getContainingFile());
453         breakpointManager.addLineBreakpoint(document, 3);
454       }
455     }, ApplicationManager.getApplication().getDefaultModalityState());
456   }
457
458   protected void createHelloWorldProcessWithBreakpoint() throws ExecutionException, InterruptedException, InvocationTargetException {
459     createLocalProcess("HelloWorld");
460
461     createBreakpointInHelloWorld();
462   }
463
464   @Override
465   protected DebugProcessImpl getDebugProcess() {
466     return myDebuggerSession != null ? myDebuggerSession.getProcess() : null;
467   }
468
469   public DebuggerSession getDebuggerSession() {
470     return myDebuggerSession;
471   }
472
473   protected DebuggerSession attachVirtualMachine(RunProfileState state,
474                                                  ExecutionEnvironment environment,
475                                                  RemoteConnection remoteConnection,
476                                                  boolean pollConnection) throws ExecutionException {
477     final DebuggerSession debuggerSession =
478       DebuggerManagerEx.getInstanceEx(myProject).attachVirtualMachine(new DefaultDebugEnvironment(environment, state, remoteConnection, pollConnection));
479     XDebuggerManager.getInstance(myProject).startSession(environment, new XDebugProcessStarter() {
480       @Override
481       @NotNull
482       public XDebugProcess start(@NotNull XDebugSession session) {
483         return JavaDebugProcess.create(session, debuggerSession);
484       }
485     });
486     return debuggerSession;
487   }
488
489   public class MockConfiguration implements ModuleRunConfiguration {
490     @Override
491     @NotNull
492     public Module[] getModules() {
493       if (myModule != null) {
494         return new Module[]{myModule};
495       }
496       else {
497         return Module.EMPTY_ARRAY;
498       }
499     }
500
501     @Override
502     public Icon getIcon() {
503       return null;
504     }
505
506     @Override
507     public ConfigurationFactory getFactory() {
508       return null;
509     }
510
511     @Override
512     public void setName(String name) { }
513
514     @NotNull
515     @Override
516     public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
517       throw new UnsupportedOperationException();
518     }
519
520     @Override
521     public Project getProject() {
522       return null;
523     }
524
525     @Override
526     @NotNull
527     public ConfigurationType getType() {
528       return UnknownConfigurationType.INSTANCE;
529     }
530
531     @Override
532     public ConfigurationPerRunnerSettings createRunnerSettings(ConfigurationInfoProvider provider) {
533       return null;
534     }
535
536     @Override
537     public SettingsEditor<ConfigurationPerRunnerSettings> getRunnerSettingsEditor(ProgramRunner runner) {
538       return null;
539     }
540
541     @Override
542     public RunConfiguration clone() {
543       return null;
544     }
545
546     @Override
547     public int getUniqueID() {
548       return 0;
549     }
550
551     @Override
552     public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
553       return null;
554     }
555
556     @Override
557     public String getName() {
558       return "";
559     }
560
561     @Override
562     public void checkConfiguration() throws RuntimeConfigurationException { }
563
564     @Override
565     public void readExternal(Element element) throws InvalidDataException { }
566
567     @Override
568     public void writeExternal(Element element) throws WriteExternalException { }
569   }
570 }