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