|
2 | 2 |
|
3 | 3 | ### Background
|
4 | 4 |
|
5 |
| -We have split the UnitTestBot machinery into three processes. See [doc about processes](../RD%20for%20UnitTestBot.md). |
6 |
| -This approach has improved UnitTestBot capabilities, e.g. provided support for various JVMs and scenarios, but also complicated the debugging flow. |
| 5 | +We have split the UnitTestBot machinery into three processes. See the [document on UnitTestBot multiprocess |
| 6 | +architecture](../RD%20for%20UnitTestBot.md). |
| 7 | +This approach has improved UnitTestBot capabilities, e.g., provided support for various JVMs and scenarios but also |
| 8 | +complicated the debugging flow. |
7 | 9 |
|
8 | 10 | These are UnitTestBot processes (according to the execution order):
|
9 | 11 |
|
10 |
| -* IDE process |
11 |
| -* Engine process |
12 |
| -* Instrumented process |
| 12 | +* _IDE process_ |
| 13 | +* _Engine process_ |
| 14 | +* _Instrumented process_ |
13 | 15 |
|
14 |
| -Usually, main problems happen in the Engine process, but it is not the process we run first. |
15 |
| -The most straightforward way to debug the Engine process is the following. |
| 16 | +Usually, the main problems happen in the _Engine process_, but it is not the process we run first. |
| 17 | +See how to debug UnitTestBot processes effectively. |
16 | 18 |
|
17 |
| -### Enable Debugging |
| 19 | +### Enable debugging |
18 | 20 |
|
19 |
| -IDE debugging is pretty straightforward - start `runIde` task in `utbot-intellij` project from IDEA with debug. |
| 21 | +Debugging the _IDE process_ is pretty straightforward: start the debugger session (**Shift+F9**) for the `runIde` |
| 22 | +Gradle task in `utbot-intellij` project from your IntelliJ IDEA. |
| 23 | + |
| 24 | +To debug the _Engine process_ and the _Instrumented process_, you need to enable the debugging options: |
| 25 | +1. Open [`UtSettings.kt`](../../utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt). |
| 26 | +2. There are two similar options: `runEngineProcessWithDebug` and `runInstrumentedProcessWithDebug` — enable the |
| 27 | + relevant one(s). There are two ways to do this: |
| 28 | + * You can create the `~/.utbot/settings.properties` file and write the following: |
20 | 29 |
|
21 |
| -For engine and instrumented processes you need to enable some options: |
22 |
| -1. Open [`UtSettings.kt`](../../utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt) |
23 |
| -2. There are 2 similar options: `runEngineProcessWithDebug` and `runInstrumentedProcessWithDebug`. |
24 |
| -3. Enable for processes you need to debug. It can be done in 2 ways: |
25 |
| - * Can create `~/.utbot/settings.properties` file and write following: |
26 | 30 | ```
|
27 | 31 | runEngineProcessWithDebug=true
|
28 | 32 | runInstrumentedProcessWithDebug=true
|
29 | 33 | ```
|
30 |
| - After you will need to restart IDEA you want to debug. |
31 |
| - * ***Discouraged***: change in source file, but this will involve moderate project recompilation. |
32 |
| -4. Additionally, you can set additional options for JDWP agent if debug is enabled: |
33 |
| - * `engineProcessDebugPort` and `instrumentedProcessDebugPort` - port for debugging. |
34 |
| - Default values - 5005 for Engine and 5006 for Instrumented processes. |
35 |
| - * `suspendEngineProcessExecutionInDebugMode` and `suspendInstrumentedProcessExecutionInDebugMode` - whether JDWP agent should |
36 |
| - suspend process until debugger is connected. |
37 |
| - |
38 |
| - More formally, if debug is enabled following switch is added to engine process JVM at start by default: |
39 |
| - |
| 34 | + Then restart the IntelliJ IDEA instance you want to debug. |
| 35 | + |
| 36 | + * **Discouraged**: you can change the options in the source file, but this will involve moderate project |
| 37 | + recompilation. |
| 38 | +4. You can set additional options for the Java Debug Wire Protocol (JDWP) agent if debugging is enabled: |
| 39 | + * `engineProcessDebugPort` and `instrumentedProcessDebugPort` are the ports for debugging. |
| 40 | + |
| 41 | + Default values: |
| 42 | + - 5005 for the _Engine process_ |
| 43 | + - 5006 for the _Instrumented process_ |
| 44 | + |
| 45 | + * `suspendEngineProcessExecutionInDebugMode` and `suspendInstrumentedProcessExecutionInDebugMode` define whether |
| 46 | + the JDWP agent should suspend the process until the debugger is connected. |
| 47 | + |
| 48 | + More formally, if debugging is enabled, the following switch is added to the _Engine process_ JVM at the start by |
| 49 | + default: |
40 | 50 | ```
|
41 |
| - -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=5005" |
| 51 | + "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=5005" |
42 | 52 | ```
|
43 |
| - These options regulate values for parts `suspend` and `address`, for example with following in `~/.utbot/settings.properties`: |
| 53 | + |
| 54 | + These options set `suspend` and `address` values. For example, with the following options in `~/.utbot/settings.properties`: |
44 | 55 | ```
|
45 | 56 | runEngineProcessWithDebug=true
|
46 | 57 | engineProcessDebugPort=12345
|
47 | 58 | suspendEngineProcessExecutionInDebugMode=false
|
48 | 59 | ```
|
49 |
| - result switch will be: |
| 60 | + the resulting switch will be: |
50 | 61 | ```
|
51 |
| - -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,quiet=y,address=12345" |
| 62 | + "-agentlib:jdwp=transport=dt_socket,server=n,suspend=n,quiet=y,address=12345" |
52 | 63 | ```
|
53 |
| - See `org.utbot.intellij.plugin.process.EngineProcess.Companion.getDebugArgument` |
54 |
| -5. For information about logs - see [this](InterProcessLogging.md). |
| 64 | + See `org.utbot.intellij.plugin.process.EngineProcess.Companion.debugArgument` for switch implementation. |
| 65 | +5. For information about logs, refer to the [Interprocess logging](InterProcessLogging.md) guide. |
55 | 66 |
|
56 | 67 | ### Run configurations for debugging the Engine process
|
57 | 68 |
|
58 |
| -There are 3 basic run configurations: |
59 |
| -1. `Run IDE` - run plugin in IDEA |
60 |
| -2. `Utility configuration/Listen for Instrumented Process` - listen on 5006 port if instrumented process is available for debug |
61 |
| -3. `Utility configuration/Listen for Engine Process` - listen on 5005 port if engine process is available for debug |
| 69 | +There are three basic run configurations: |
| 70 | +1. `Run IDE` configuration allows running the plugin in IntelliJ IDEA. |
| 71 | +2. `Utility Configurations/Listen for Instrumented Process` configuration allows listening to port 5006 to check if |
| 72 | + the _Instrumented process_ is available for debugging. |
| 73 | +3. `Utility Configurations/Listen for Engine Process` configuration allows listening to port 5005 to check if the _Engine process_ is available for debugging. |
62 | 74 |
|
63 |
| -On top of them, there are 3 compound run configurations for debugging: |
64 |
| -1. `Debug Engine Process` and `Debug Instrumented Process` - combo for debug IDE and selected process |
65 |
| -3. `Debug All` - debug all 3 processes. |
| 75 | +On top of them, there are three compound run configurations for debugging: |
| 76 | +1. `Debug Engine Process` and `Debug Instrumented Process` — a combination for debugging the _IDE process_ and |
| 77 | + the selected process. |
| 78 | +3. `Debug All` — a combination for debugging all three processes. |
66 | 79 |
|
67 |
| -For debug configurations to work you need to provide required properties in `~/.utbot/settings.properties`. |
68 |
| -If you either change port and/or suspend mode - do review utility configuration to change default values as well. |
| 80 | +To make debug configurations work properly, you need to set the required properties in `~/.utbot/settings.properties`. If you change the _port number_ and/or the _suspend mode_, do change these default values in the corresponding Utility Configuration. |
69 | 81 |
|
70 | 82 | ### How to debug
|
71 | 83 |
|
72 |
| -Let's see through example of how to debug IDE to engine process communication. |
| 84 | +Let's walk through an example illustrating how to debug the "_IDE process_ → _Engine process_" communication. |
73 | 85 |
|
74 |
| -1. In your current IntelliJ IDEA with source, use breakpoints to define where the program needs to be stopped. For example, set the breakpoints at `EngineProcess.generate` |
75 |
| - and somewhere in `watchdog.wrapActiveCall(generate)`. |
76 |
| -2. Select `Debug Engine Process` configuration, add required parameters to `~/.utbot/settings.properties` and start debug. |
77 |
| -3. Generate tests with UnitTestBot in the debug IDE instance. |
78 |
| -4. The debug IDE instance will stop generation (if you have not changed the debug parameters). If you take no action, test generation will be cancelled by timeout. |
79 |
| -5. When the Engine process started (build processes have finished, and the progress bar says: _"Generate tests: read |
80 |
| - classes"_), there will be |
81 |
| -6. Wait for the program to be suspended upon reaching the first breakpoint in Engine proces. |
82 |
| -7. If symbolic execution is not turned on - часть магии может нахуй не случиться |
| 86 | +1. In your current IntelliJ IDEA with source code, use breakpoints to define where the program needs to be stopped. For example, set the breakpoints at `EngineProcess.generate` and somewhere in `watchdog.wrapActiveCall(generate)`. |
| 87 | +2. Select the `Debug Engine Process` configuration, add the required parameters to `~/.utbot/settings.properties` and |
| 88 | + start the debugger session. |
| 89 | +3. Generate tests with UnitTestBot in the debug IDE instance. Make sure symbolic execution is turned on, otherwise some processes do not even start. |
| 90 | +4. The debug IDE instance will stop generation (if you have not changed the debug parameters). If you take no action, test generation will be canceled by timeout. |
| 91 | +5. When the _Engine process_ has started (build processes have finished, and the progress bar says: _"Generate |
| 92 | + tests: read classes"_), there will be another debug window — "Listen for Engine Process", — which automatically |
| 93 | + connects and starts debugging. |
| 94 | +6. Wait for the program to be suspended upon reaching the first breakpoint in the _Engine process_. |
83 | 95 |
|
84 | 96 | ### Interprocess call mapping
|
85 | 97 |
|
86 |
| -Now you are standing on a breakpoint in the IDE process, for example, the process stopped on: |
| 98 | +Now you are standing on a breakpoint in the _IDE process_, for example, the process stopped on: |
87 | 99 |
|
88 |
| - `EngineProcess.generate()` |
| 100 | + EngineProcess.generate() |
89 | 101 |
|
90 |
| -If you would go along execution, it reaches the next line (you are still in the IDE process): |
| 102 | +If you go along the execution, it reaches the next line (you are still in the _IDE process_): |
91 | 103 |
|
92 |
| - `engineModel.generate.startBlocking(params)` |
| 104 | + engineModel.generate.startBlocking(params) |
93 | 105 |
|
94 |
| -It seems that the test generation itself should occur in the Engine process and there should be an entry point in the Engine process. |
95 |
| -How can we find it? |
| 106 | +It seems that test generation itself should occur in the _Engine process_ and there should be an entry point in the _Engine process_. |
| 107 | +How can we find it? |
96 | 108 |
|
97 |
| -Standing on the breakpoint `engineModel.generate.startBlocking(params)`, you may right-click in IDE on `EngineProcessModel.generate` and **Go to Declaration or |
98 |
| -Usage**. This would navigate to the definition of `RdCall` (which is responsible for cross-process communication) in file `EngineProcesModel.Generated.kt`. |
| 109 | +Standing on the breakpoint at `engineModel.generate.startBlocking(params)`, right-click on |
| 110 | +`EngineProcessModel.generate` and **Go to** > **Declaration or Usages**. This navigates to the `RdCall` definition (which is |
| 111 | +responsible for cross-process communication) in the `EngineProcesModel.Generated.kt` file. |
99 | 112 |
|
100 | 113 | Now **Find Usages** for `EngineProcessModel.generate` and see the point where `RdCall` is passed to the next method:
|
101 | 114 |
|
102 | 115 | watchdog.wrapActiveCall(generate)
|
103 | 116 |
|
104 |
| -This is the point where `RdCall` is called in the Engine process. |
| 117 | +This is the point where `RdCall` is called in the _Engine process_. |
105 | 118 |
|
106 |
| -Actually you could have skipped the previous step and used **Find Usages** right away, but it is useful to know where `RdCall` is defined. |
| 119 | +You could have skipped the previous step and used **Find Usages** right away, but it is useful to know |
| 120 | +where `RdCall` is defined. |
107 | 121 |
|
108 | 122 | If you are interested in the trailing lambda of `watchdog.wrapActiveCall(generate)`, set the breakpoint here.
|
0 commit comments