Skip to content
Open
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 @@ -66,7 +66,8 @@ class Test2Code(
pageSize = configuration.parameters[Test2CodeParameterDefinitions.COVERAGE_SEND_PAGE_SIZE],
sender = sender,
collectReleasedProbes = { coverageManager.pollRecorded() },
collectUnreleasedProbes = { coverageManager.getUnreleased() }
collectUnreleasedProbes = { coverageManager.getUnreleased() },
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,7 @@ open class CoverageManager(
) : IProbesProxy,
ICoverageRecorder by threadCoverageRecorder {

private val classProbePositions: ConcurrentHashMap<Long, Map<String, Pair<Int, Int>>> = ConcurrentHashMap()
val classMethodsMetadata: ConcurrentHashMap<Long, ClassMethodsMetadata> = ConcurrentHashMap()

override fun invoke(
id: Long,
Expand All @@ -39,15 +39,14 @@ open class CoverageManager(
id = id,
probes = AgentProbes(probeCount),
sessionId = coverage.context.sessionId,
testId = coverage.context.testId,
probePositions = classProbePositions[id]!! // TODO do not throw
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 @@ -24,6 +24,7 @@ import com.epam.drill.agent.test2code.common.api.MethodCoverage
import com.epam.drill.agent.test2code.common.api.toBitSet
import com.epam.drill.agent.test2code.common.transport.CoveragePayload
import kotlinx.serialization.KSerializer
import java.util.concurrent.ConcurrentHashMap

interface CoverageSender {
fun startSendingCoverage()
Expand All @@ -40,7 +41,8 @@ class IntervalCoverageSender(
private val pageSize: Int,
private val sender: AgentMessageSender = StubSender(),
private val collectReleasedProbes: () -> Sequence<ExecDatum> = { emptySequence() },
private val collectUnreleasedProbes: () -> Sequence<ExecDatum> = { emptySequence() }
private val collectUnreleasedProbes: () -> Sequence<ExecDatum> = { emptySequence() },
private val classMethodsMetadata: ConcurrentHashMap<Long, ClassMethodsMetadata>
) : CoverageSender {
private val scheduledThreadPool = Executors.newSingleThreadScheduledExecutor()
private val destination = AgentMessageDestination("POST", "coverage")
Expand Down Expand Up @@ -75,11 +77,17 @@ class IntervalCoverageSender(
*/
private fun sendProbes(dataToSend: Sequence<ExecDatum>) {
dataToSend
.flatMap { it.probePositions.mapNotNull { (signature, positions) ->
val methodProbes = it.probes.values.copyOfRange(positions.first, positions.first + positions.second).toBitSet()
if (!methodProbes.isEmpty) null
.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,
bodyChecksum = metadata.bodyChecksum,
testId = it.testId,
testSessionId = it.sessionId,
probes = methodProbes
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 @@ -30,6 +30,5 @@ data class ExecDatum(
val id: ClassId,
val probes: AgentProbes,
val sessionId: String,
val testId: String,
val probePositions: Map<String, Pair<Int, Int>>
val testId: String
)
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