Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Test2Code(
sender = sender,
collectReleasedProbes = { coverageManager.pollRecorded() },
collectUnreleasedProbes = { coverageManager.getUnreleased() },
classProbePositions = coverageManager.classProbePositions
classMethodsMetadata = coverageManager.classMethodsMetadata
)
private val coverageCollectionEnabled = configuration.parameters[COVERAGE_COLLECTION_ENABLED]
private val classScanningEnabled = configuration.parameters[Test2CodeParameterDefinitions.CLASS_SCANNING_ENABLED]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,7 @@ fun parseAstClass(className: String, classBytes: ByteArray): List<AstMethod> {
}
}

private fun AstMethod.classSignature() =
"${name}/${params}/${returnType}"

private fun AstMethod.classSignature() = "${classname}:${name}:${params}:${returnType}"

private fun getReturnType(methodNode: MethodNode): String {
val returnTypeDesc: String = Type.getReturnType(methodNode.desc).descriptor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,19 @@ import java.io.ByteArrayInputStream

val logger = KotlinLogging.logger { }

internal fun calculateMethodsChecksums(
fun calculateMethodsChecksums(
classBytes: ByteArray,
className: String
): Map<String, String> = ClassParser(ByteArrayInputStream(classBytes), className)
.parse()
.methods
// Filter needed for skipping interfaces, which have no opcodes for calculating checksum
.filter { it.code != null }
.map { method -> method.classSignature() to calculateChecksum(method, className) }
.map { method -> method.classSignature(className) to calculateChecksum(method, className) }
.filter { it.second != "" }
.associate { it.first to it.second }

fun Method.classSignature() =
"${name}/${argumentTypes.asSequence().map { type -> type.toString() }.joinToString(separator = ",")}/${returnType}"
fun Method.classSignature(className: String) = "${className}:${name}:${argumentTypes.asSequence().map { type -> type.toString() }.joinToString(separator = ",")}:${returnType}"

private fun calculateChecksum(
method: Method,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ open class CoverageManager(
) : IProbesProxy,
ICoverageRecorder by threadCoverageRecorder {

val classProbePositions: ConcurrentHashMap<Long, Map<String, Pair<Int, Int>>> = ConcurrentHashMap()
// TODO doesn't make much sense to store it here, if we use it only in coverage sender
val classMethodsMetadata: ConcurrentHashMap<Long, ClassMethodsMetadata> = ConcurrentHashMap()

override fun invoke(
id: Long,
Expand All @@ -39,14 +40,14 @@ open class CoverageManager(
id = id,
probes = AgentProbes(probeCount),
sessionId = coverage.context.sessionId,
testId = coverage.context.testId,
testId = coverage.context.testId
)
}
return execDatum.probes
}

override fun addProbePositions(classId: Long, probePositions: Map<String, Pair<Int, Int>>) {
classProbePositions[classId] = probePositions
override fun addClassMethodsMetadata(classId: Long, methodsMetadata: ClassMethodsMetadata) {
classMethodsMetadata[classId] = methodsMetadata
}

override fun pollRecorded(): Sequence<ExecDatum> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class IntervalCoverageSender(
private val sender: AgentMessageSender = StubSender(),
private val collectReleasedProbes: () -> Sequence<ExecDatum> = { emptySequence() },
private val collectUnreleasedProbes: () -> Sequence<ExecDatum> = { emptySequence() },
private val classProbePositions: ConcurrentHashMap<Long, Map<String, Pair<Int, Int>>>
private val classMethodsMetadata: ConcurrentHashMap<Long, ClassMethodsMetadata>
) : CoverageSender {
private val scheduledThreadPool = Executors.newSingleThreadScheduledExecutor()
private val destination = AgentMessageDestination("POST", "coverage")
Expand Down Expand Up @@ -77,29 +77,25 @@ class IntervalCoverageSender(
*/
private fun sendProbes(dataToSend: Sequence<ExecDatum>) {
dataToSend
.mapNotNull {
classProbePositions[it.id]?.let { positionsByMethod ->
it to positionsByMethod
} ?: run {
logger.warn("No probe positions for class id=${it.id}")
null
}
}
.flatMap { (datum, positionsByMethod) ->
positionsByMethod.mapNotNull { (signature, positions) ->
val methodProbes =
datum.probes.values
.copyOfRange(positions.first, positions.first + positions.second)
.toBitSet()
.flatMap {
classMethodsMetadata[it.id]
?.mapNotNull { (signature, metadata) ->
val methodProbes = it.probes.values.copyOfRange(
metadata.probesStartPos,
metadata.probesStartPos + metadata.probesCount
).toBitSet()

if (methodProbes.isEmpty) null
else MethodCoverage(
signature = signature,
testId = datum.testId,
testSessionId = datum.sessionId,
probes = methodProbes
)
}
if (methodProbes.isEmpty) null
else MethodCoverage(
signature = signature,
bodyChecksum = metadata.bodyChecksum,
testId = it.testId,
testSessionId = it.sessionId,
probes = methodProbes
)
}
?.asSequence()
?: emptySequence()
}
.chunked(pageSize)
.forEach { sender.send(destination, CoveragePayload(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import com.epam.drill.agent.jacoco.DrillClassProbesAdapter
import com.epam.drill.agent.jacoco.DrillDuplicateFrameEliminator
import com.epam.drill.agent.jacoco.DrillMethodInstrumenter
import com.epam.drill.agent.test2code.classparsing.ClassProbeCounter
import com.epam.drill.agent.test2code.classparsing.ProbeCounter
import com.epam.drill.agent.test2code.classparsing.calculateMethodsChecksums
import org.jacoco.core.internal.data.CRC64
import org.jacoco.core.internal.flow.*
import org.jacoco.core.internal.instr.*
Expand All @@ -47,9 +47,17 @@ class DrillInstrumenter(
val counter = ClassProbeCounter(className)
reader.accept(DrillClassProbesAdapter(counter, false), 0)

probesProxy.addProbePositions(classId, counter.methods.associate { m ->
"${m.classname}:${m.name}:${m.params}:${m.returnType}" to Pair(m.probesStartPos, m.probesCount)
})
val bodyChecksums = calculateMethodsChecksums(initialBytes, className)
val classMethodsMetadata: ClassMethodsMetadata = counter.methods.associate { m ->
val signature = "${m.classname}:${m.name}:${m.params}:${m.returnType}"
signature to ClassMethodMetadata(
probesStartPos = m.probesStartPos,
probesCount = m.probesCount,
bodyChecksum = bodyChecksums[signature] ?: "" // interface methods don't have a body
)
}

probesProxy.addClassMethodsMetadata(classId, classMethodsMetadata)

val genId = classCounter.incrementAndGet()
val probeCount = counter.count
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,16 @@ import com.epam.drill.agent.jacoco.AgentProbes

interface IProbesProxy {
fun invoke(id: ClassId, num: Int, name: String, probeCount: Int): AgentProbes
fun addProbePositions(classId: Long, probePositions: Map<String, Pair<Int,Int>>)
fun addClassMethodsMetadata(classId: Long, methodsMetadata: ClassMethodsMetadata)
}

typealias ClassMethodsMetadata = Map<String, ClassMethodMetadata>
data class ClassMethodMetadata(
val probesStartPos: Int,
val probesCount: Int,
val bodyChecksum: String
)

const val SESSION_CONTEXT_NONE = "SESSION_CONTEXT_NONE"
const val TEST_CONTEXT_NONE = "TEST_CONTEXT_NONE"
const val SESSION_CONTEXT_AMBIENT = "GLOBAL"
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading