Skip to content

Commit

Permalink
Merge test method duration for a given classes
Browse files Browse the repository at this point in the history
  • Loading branch information
jan-goral committed Jul 2, 2021
1 parent 2d5fc46 commit 1ebb01b
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import flank.corellium.domain.RunTestCorelliumAndroid.Args.DefaultOutputDir
import flank.corellium.domain.RunTestCorelliumAndroid.LoadPreviousDurations
import flank.corellium.domain.step
import flank.junit.calculateTestCaseDurations
import flank.junit.mergeTestCases

/**
* The step is searching result directory for JUnitReport.xml.
Expand All @@ -21,14 +22,18 @@ internal fun RunTestCorelliumAndroid.Context.loadPreviousDurations() = step(Load
if (args.outputDir.startsWith(DefaultOutputDir.ROOT)) DefaultOutputDir.ROOT
else args.outputDir

val classesCases: Set<String> =
testCases.values.flatten().filter { '#' !in it }.toSet()

copy(
previousDurations = junit.parseTestResults(directoryToScan)
.take(args.scanPreviousDurations).toList()
.apply { LoadPreviousDurations.Searching(size).out() }
.map { suite -> suite.mergeTestCases(classesCases) }
.flatten()
.calculateTestCaseDurations()
.withDefault { previousDurations.getValue(it) }
.also { durations -> printStats(durations.keys).out() }
.apply { printStats(keys).out() }
)
}

Expand Down
7 changes: 7 additions & 0 deletions tool/junit/src/main/kotlin/flank/junit/JUnit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
import flank.junit.internal.calculateMedianDurations
import flank.junit.internal.mergeDurations
import flank.junit.internal.parseJUnitTestResults
import flank.junit.mapper.TimeSerializer
import flank.junit.mapper.mapToTestSuites
Expand Down Expand Up @@ -36,6 +37,12 @@ fun JUnit.Report.writeAsXml(writer: Writer) {
xmlPrettyWriter.writeValue(writer, this)
}

/**
* Merge [JUnit.TestResult] test methods by class names to accumulate duration and return them as classes of test methods.
*/
fun List<JUnit.TestResult>.mergeTestCases(byClasses: Set<String>): List<JUnit.TestResult> =
mergeDurations(byClasses)

/**
* Calculate associate full test cases names to calculated duration.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal fun List<JUnit.TestResult>.calculateMedianDurations(): Map<String, Long
.groupBy(Pair<String, Long>::first, Pair<String, Long>::second)
.mapValues { (_, durations) -> durations.median() }

private val JUnit.TestResult.fullName get() = "$className#$testName"
private val JUnit.TestResult.fullName get() = className + if (testName.isBlank()) "" else "#$testName"

private val JUnit.TestResult.duration get() = (endsAt - startAt)

Expand Down
17 changes: 17 additions & 0 deletions tool/junit/src/main/kotlin/flank/junit/internal/MergeDurations.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package flank.junit.internal

import flank.junit.JUnit

internal fun List<JUnit.TestResult>.mergeDurations(
forClasses: Set<String>
): List<JUnit.TestResult> =
if (forClasses.isEmpty()) this
else groupBy { testResult -> testResult.className in forClasses }.run {
getOrDefault(false, emptyList()) + getOrDefault(true, emptyList())
.groupBy { testResult -> testResult.className }.values
.map { group ->
group.sortedBy { it.startAt }
.reduce { acc, testResult -> acc.copy(endsAt = testResult.endsAt) }
.run { copy(testName = "") }
}
}
8 changes: 6 additions & 2 deletions tool/junit/src/main/kotlin/flank/junit/mapper/Structural.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ internal fun List<JUnit.TestResult>.mapToTestSuites(): List<JUnit.Suite> = this

internal fun List<JUnit.Suite>.mapToTestResults(): List<JUnit.TestResult> =
flatMap { suite ->
var startAt: Long
var endAt: Long = 0
suite.testcases.map { case ->
startAt = endAt
endAt = startAt + (case.time * 1000).toLong()
JUnit.TestResult(
suiteName = suite.name,
testName = case.name,
className = case.classname,
startAt = 0,
endsAt = (case.time * 1000).toLong(),
startAt = startAt.also { startAt = endAt },
endsAt = endAt,
status = when {
case.error.isNotEmpty() -> JUnit.TestResult.Status.Error
case.failure.isNotEmpty() -> JUnit.TestResult.Status.Failed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package flank.junit.internal

import flank.junit.JUnit
import flank.junit.mergeTestCases
import org.junit.Assert
import org.junit.Test

class MergeDurationsKtTest {

@Test
fun test() {
// given
val results = listOf(
result("a", "a", 0, 10),
result("b", "b[0]", 10, 110),
result("b", "b[1]", 110, 120),
result("b", "b[2]", 120, 140),
result("c", "c", 140, 440),
result("d", "d[name: a]", 440, 470),
result("d", "d[name: b]", 470, 500),
)

val expected = listOf(
result("a", "a", 0, 10),
result("c", "c", 140, 440),
result("b", "", 10, 140),
result("d", "", 440, 500),
)

// when
val actual = results.mergeTestCases(setOf("b", "d"))

// then
Assert.assertEquals(expected, actual)
}
}

private fun result(
className: String,
name: String,
start: Long,
end: Long,
) = JUnit.TestResult(
className = className,
testName = name,
startAt = start,
endsAt = end,
stack = emptyList(),
status = JUnit.TestResult.Status.Passed,
suiteName = "",
)

0 comments on commit 1ebb01b

Please sign in to comment.