[debugger] Implement additional logging for flaky tests

GitOrigin-RevId: ec1eb573ee756dc0d16ee0dcada086db0625e277
This commit is contained in:
Alexey Merkulov
2024-07-09 18:00:03 +02:00
committed by intellij-monorepo-bot
parent 60ab01aec0
commit 9592fceda6
7 changed files with 78 additions and 18 deletions

View File

@@ -18,10 +18,7 @@ import com.intellij.debugger.requests.Requestor;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.statistics.DebuggerStatistics;
import com.intellij.debugger.statistics.StatisticsStorage;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
import com.intellij.debugger.ui.breakpoints.InstrumentationTracker;
import com.intellij.debugger.ui.breakpoints.StackCapturingLineBreakpoint;
import com.intellij.debugger.ui.breakpoints.SyntheticBreakpoint;
import com.intellij.debugger.ui.breakpoints.*;
import com.intellij.debugger.ui.overhead.OverheadProducer;
import com.intellij.debugger.ui.overhead.OverheadTimings;
import com.intellij.ide.BrowserUtil;
@@ -646,6 +643,22 @@ public class DebugProcessEvents extends DebugProcessImpl {
final SuspendManager suspendManager = getSuspendManager();
final LocatableEventRequestor requestor = (LocatableEventRequestor)RequestManagerImpl.findRequestor(event.request());
boolean isDebugLogBreakpoint = requestor instanceof InternalDebugLoggingRequestor dReq && dReq.isDebugLogBreakpoint();
if (isDebugLogBreakpoint) {
String firstArgument;
try {
firstArgument = suspendContext.getEventThread().frame(0).getArgumentValues().get(0).toString();
}
catch (Throwable e) {
firstArgument = e.getMessage();
}
LOG.debug("Debug log breakpoint: " + firstArgument);
suspendManager.voteResume(suspendContext);
return;
}
ThreadReferenceProxyImpl threadProxy = suspendContext.getThread();
boolean isEvaluationOnCurrentThread = threadProxy != null && threadProxy.isEvaluating();
if ((isEvaluationOnCurrentThread || myThreadBlockedMonitor.isInResumeAllMode()) &&

View File

@@ -75,7 +75,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Stream;
public abstract class Breakpoint<P extends JavaBreakpointProperties> implements FilteredRequestor, ClassPrepareRequestor, OverheadProducer {
public abstract class Breakpoint<P extends JavaBreakpointProperties> implements FilteredRequestor, ClassPrepareRequestor, OverheadProducer, InternalDebugLoggingRequestor {
public static final Key<Breakpoint<?>> DATA_KEY = Key.create("JavaBreakpoint");
private static final Key<Long> HIT_COUNTER = Key.create("HIT_COUNTER");
@@ -86,6 +86,8 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
@NonNls private static final String LOG_MESSAGE_OPTION_NAME = "LOG_MESSAGE";
protected boolean myCachedVerifiedState = false;
private boolean myIsDebugLogBreakpoint;
protected Breakpoint(@NotNull Project project, XBreakpoint<P> xBreakpoint) {
myProject = project;
myXBreakpoint = xBreakpoint;
@@ -810,4 +812,13 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
protected void fireBreakpointChanged() {
((XBreakpointBase<?, ?, ?>)myXBreakpoint).fireBreakpointChanged();
}
public void setIsDebugLogBreakpoint(boolean isDebugLogBreakpoint) {
myIsDebugLogBreakpoint = isDebugLogBreakpoint;
}
@Override
public boolean isDebugLogBreakpoint() {
return myIsDebugLogBreakpoint;
}
}

View File

@@ -0,0 +1,12 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.debugger.ui.breakpoints;
import org.jetbrains.annotations.ApiStatus;
/** It is used to investigate flaky test behavior in complex cases */
@ApiStatus.Internal
public interface InternalDebugLoggingRequestor {
default boolean isDebugLogBreakpoint() {
return false;
}
}

View File

@@ -106,8 +106,7 @@ object CoroutineBreakpointFacility {
breakpoint.createRequest(debugProcess)
debugProcess.setSteppingBreakpoint(breakpoint)
val filterThread = debugProcess.requestsManager.filterThread
thisLogger().debug("Resume breakpoint for $method in thread $filterThread")
thisLogger().debug("Resume breakpoint for $method in context $context")
return true
}

View File

@@ -2,16 +2,14 @@
package org.jetbrains.kotlin.idea.debugger.test.util
import com.intellij.debugger.DebuggerInvocationUtil
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.ui.breakpoints.Breakpoint
import com.intellij.debugger.ui.breakpoints.BreakpointManager
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType
import com.intellij.debugger.ui.breakpoints.LineBreakpoint
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.vfs.VirtualFile
@@ -27,6 +25,7 @@ import com.intellij.xdebugger.breakpoints.XBreakpointType
import com.intellij.xdebugger.breakpoints.XLineBreakpointType
import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties
import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinLineBreakpointType
import org.jetbrains.kotlin.idea.debugger.core.DebuggerUtils.isKotlinSourceFile
@@ -35,9 +34,7 @@ import org.jetbrains.kotlin.idea.debugger.core.breakpoints.KotlinFunctionBreakpo
import org.jetbrains.kotlin.idea.debugger.core.breakpoints.KotlinFunctionBreakpointType
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved
import java.util.*
import javax.swing.SwingUtilities
internal class BreakpointCreator(
private val project: Project,
@@ -94,6 +91,9 @@ internal class BreakpointCreator(
comment.startsWith("//FunctionBreakpoint!") -> {
createFunctionBreakpoint(breakpointManager, file, lineIndex, false)
}
comment.startsWith("//LogFirstArgumentBreakpoint!") -> {
createLogFirstArgumentBreakpoint(breakpointManager, file, lineIndex)
}
else -> throw AssertionError("Cannot create breakpoint at line ${lineIndex + 1}")
}
}
@@ -171,6 +171,22 @@ internal class BreakpointCreator(
}
}
private fun createLogFirstArgumentBreakpoint(breakpointManager: XBreakpointManager, file: PsiFile, lineIndex: Int) {
val kotlinLineBreakpointType = findBreakpointType(KotlinLineBreakpointType::class.java)
val javaBreakpoint = createBreakpointOfType(
breakpointManager,
kotlinLineBreakpointType,
lineIndex,
file.virtualFile,
null,
false,
)
javaBreakpoint?.setIsDebugLogBreakpoint(true)
if (javaBreakpoint is LineBreakpoint<*>) {
thisLogger().debug("LogFirstArgumentBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}")
}
}
private fun createLineBreakpoint(
breakpointManager: XBreakpointManager,
file: PsiFile,

View File

@@ -5,10 +5,12 @@ import kotlinx.coroutines.*
suspend fun foo(i: Int) {
println("Start foo")
coroutineScope {
trackExecution("Start for $i")
if (i == 25) {
//Breakpoint!
startMethod(i)
}
trackExecution("Middle for $i")
delay(1)
// EXPRESSION: i
// RESULT: 25: I
@@ -39,7 +41,13 @@ fun main() {
}
}
// STEP_OVER: 3
fun trackExecution(s: String) {
//LogFirstArgumentBreakpoint!
s.toString()
}
// STEP_OVER: 4
// REGISTRY: debugger.filter.breakpoints.by.coroutine.id=true
// REGISTRY: debugger.always.suspend.thread.before.switch=true
// REGISTRY: debugger.log.jdi.in.unit.tests=true

View File

@@ -1,10 +1,11 @@
LineBreakpoint created at stepThroughCoroutineScope.kt:10
LineBreakpoint created at stepThroughCoroutineScope.kt:11
Run Java
Connected to the target VM
stepThroughCoroutineScope.kt:10
stepThroughCoroutineScope.kt:12
stepThroughCoroutineScope.kt:15
stepThroughCoroutineScope.kt:16
stepThroughCoroutineScope.kt:11
stepThroughCoroutineScope.kt:13
stepThroughCoroutineScope.kt:14
stepThroughCoroutineScope.kt:17
stepThroughCoroutineScope.kt:18
Compile bytecode for i
Disconnected from the target VM