diff --git a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/Test2Code.kt b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/Test2Code.kt index 43b26b87..8adcf4fa 100644 --- a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/Test2Code.kt +++ b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/Test2Code.kt @@ -60,11 +60,14 @@ class Test2Code( groupId = configuration.agentMetadata.groupId, appId = configuration.agentMetadata.appId, instanceId = configuration.agentMetadata.instanceId, + commitSha = configuration.agentMetadata.commitSha, + buildVersion = configuration.agentMetadata.buildVersion, intervalMs = configuration.parameters[Test2CodeParameterDefinitions.COVERAGE_SEND_INTERVAL], pageSize = configuration.parameters[Test2CodeParameterDefinitions.COVERAGE_SEND_PAGE_SIZE], sender = sender, collectReleasedProbes = { coverageManager.pollRecorded() }, - collectUnreleasedProbes = { coverageManager.getUnreleased() } + collectUnreleasedProbes = { coverageManager.getUnreleased() }, + classProbePositions = coverageManager.classProbePositions ) private val coverageCollectionEnabled = configuration.parameters[COVERAGE_COLLECTION_ENABLED] private val classScanningEnabled = configuration.parameters[Test2CodeParameterDefinitions.CLASS_SCANNING_ENABLED] diff --git a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageManager.kt b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageManager.kt index 03e1f321..cb3adffa 100644 --- a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageManager.kt +++ b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageManager.kt @@ -16,6 +16,7 @@ package com.epam.drill.agent.test2code.coverage import com.epam.drill.agent.jacoco.AgentProbes +import java.util.concurrent.ConcurrentHashMap open class CoverageManager( private val threadCoverageRecorder: ICoverageRecorder = ThreadCoverageRecorder(), @@ -23,6 +24,8 @@ open class CoverageManager( ) : IProbesProxy, ICoverageRecorder by threadCoverageRecorder { + val classProbePositions: ConcurrentHashMap>> = ConcurrentHashMap() + override fun invoke( id: Long, num: Int, @@ -34,15 +37,18 @@ open class CoverageManager( val execDatum = coverage.execData.getOrPut(id) { ExecDatum( id = id, - name = name, 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>) { + classProbePositions[classId] = probePositions + } + override fun pollRecorded(): Sequence { return threadCoverageRecorder.pollRecorded() + globalCoverageRecorder.pollRecorded() } diff --git a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageSender.kt b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageSender.kt index 1c9e61ae..7c251867 100644 --- a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageSender.kt +++ b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/CoverageSender.kt @@ -20,10 +20,11 @@ import java.util.concurrent.TimeUnit import mu.KotlinLogging import com.epam.drill.agent.common.transport.AgentMessageDestination import com.epam.drill.agent.common.transport.AgentMessageSender -import com.epam.drill.agent.test2code.common.api.ClassCoverage +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() @@ -33,12 +34,15 @@ interface CoverageSender { class IntervalCoverageSender( private val groupId: String, private val appId: String, + private val commitSha: String?, + private val buildVersion: String?, private val instanceId: String, private val intervalMs: Long, private val pageSize: Int, private val sender: AgentMessageSender = StubSender(), private val collectReleasedProbes: () -> Sequence = { emptySequence() }, - private val collectUnreleasedProbes: () -> Sequence = { emptySequence() } + private val collectUnreleasedProbes: () -> Sequence = { emptySequence() }, + private val classProbePositions: ConcurrentHashMap>> ) : CoverageSender { private val scheduledThreadPool = Executors.newSingleThreadScheduledExecutor() private val destination = AgentMessageDestination("POST", "coverage") @@ -73,13 +77,39 @@ class IntervalCoverageSender( */ private fun sendProbes(dataToSend: Sequence) { dataToSend - .map { ClassCoverage( - classname = it.name, - testId = it.testId, - testSessionId = it.sessionId, - probes = it.probes.values.toBitSet()) } + .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() + + if (methodProbes.isEmpty) null + else MethodCoverage( + signature = signature, + testId = datum.testId, + testSessionId = datum.sessionId, + probes = methodProbes + ) + } + } .chunked(pageSize) - .forEach { sender.send(destination, CoveragePayload(groupId, appId, instanceId, it), CoveragePayload.serializer()) } + .forEach { sender.send(destination, CoveragePayload( + groupId = groupId, + appId = appId, + instanceId = instanceId, + commitSha = commitSha, + buildVersion = buildVersion, + coverage = it + ), CoveragePayload.serializer()) } } } diff --git a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Instrumentation.kt b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Instrumentation.kt index 2d900557..ea5c8114 100644 --- a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Instrumentation.kt +++ b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Instrumentation.kt @@ -21,6 +21,7 @@ import com.epam.drill.agent.jacoco.BooleanArrayProbeInserter.* 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 org.jacoco.core.internal.data.CRC64 import org.jacoco.core.internal.flow.* @@ -42,10 +43,14 @@ class DrillInstrumenter( val classId = CRC64.classId(initialBytes) //count probes before transformation - val counter = ProbeCounter() val reader = InstrSupport.classReaderFor(initialBytes) + 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 genId = classCounter.incrementAndGet() val probeCount = counter.count val strategy = DrillProbeStrategy( diff --git a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Models.kt b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Models.kt index c64a94c0..2920b79a 100644 --- a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Models.kt +++ b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/Models.kt @@ -28,7 +28,6 @@ typealias ExecData = ConcurrentHashMap */ data class ExecDatum( val id: ClassId, - val name: String, val probes: AgentProbes, val sessionId: String, val testId: String, diff --git a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/ProbesProvider.kt b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/ProbesProvider.kt index 29122602..7d056a94 100644 --- a/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/ProbesProvider.kt +++ b/test2code/src/main/kotlin/com/epam/drill/agent/test2code/coverage/ProbesProvider.kt @@ -21,7 +21,11 @@ import com.epam.drill.agent.jacoco.AgentProbes * Provides boolean array for the probe. * Implementations must be kotlin singleton objects. */ -typealias IProbesProxy = (ClassId, Int, String, Int) -> AgentProbes + +interface IProbesProxy { + fun invoke(id: ClassId, num: Int, name: String, probeCount: Int): AgentProbes + fun addProbePositions(classId: Long, probePositions: Map>) +} const val SESSION_CONTEXT_NONE = "SESSION_CONTEXT_NONE" const val TEST_CONTEXT_NONE = "TEST_CONTEXT_NONE" diff --git a/test2code/src/test/kotlin/com/epam/drill/agent/test2code/coverage/GlobalCoverageRecorderTest.kt b/test2code/src/test/kotlin/com/epam/drill/agent/test2code/coverage/GlobalCoverageRecorderTest.kt index af3ab796..c36734e5 100644 --- a/test2code/src/test/kotlin/com/epam/drill/agent/test2code/coverage/GlobalCoverageRecorderTest.kt +++ b/test2code/src/test/kotlin/com/epam/drill/agent/test2code/coverage/GlobalCoverageRecorderTest.kt @@ -89,10 +89,9 @@ class GlobalCoverageRecorderTest { private fun ContextCoverage.putProbes(classId: Long, vararg probes: Boolean) { execData[classId] = ExecDatum( id = classId, - name = "foo", sessionId = SESSION_CONTEXT_AMBIENT, probes = AgentProbes(initialSize = probes.size, values = booleanArrayOf(*probes)), - testId = TEST_CONTEXT_NONE + testId = TEST_CONTEXT_NONE, ) }