Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add overhead time to junit test case report #684

Merged
merged 3 commits into from
Mar 30, 2020
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
1 change: 1 addition & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## next (unreleased)
- [#687](https://github.com/Flank/flank/pull/687) Debug message printed after every command. ([pawelpasterz](https://github.com/pawelpasterz))
- [#684](https://github.com/Flank/flank/pull/684) Add overhead time to junit test case report. ([jan-gogo](https://github.com/jan-gogo))
- [#666](https://github.com/Flank/flank/pull/666) Use API instead of XML for result parsing for android. ([jan-gogo](https://github.com/jan-gogo))
- [#678](https://github.com/Flank/flank/pull/678) Skip Bugsnag initialization if user disabled gcloud analytics. ([pawelpasterz](https://github.com/pawelpasterz))
- [#672](https://github.com/Flank/flank/pull/672) Flank timeout feature. ([pawelpasterz](https://github.com/pawelpasterz))
Expand Down
14 changes: 10 additions & 4 deletions test_runner/src/main/kotlin/ftl/reports/api/CreateJUnitTestCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,28 @@ import ftl.reports.xml.model.JUnitTestCase

internal fun createJUnitTestCases(
testCases: List<TestCase>,
toolResultsStep: ToolResultsStep
toolResultsStep: ToolResultsStep,
overheadTime: Double
): List<JUnitTestCase> = testCases.map { testCase ->
createJUnitTestCase(testCase, toolResultsStep)
createJUnitTestCase(
testCase = testCase,
toolResultsStep = toolResultsStep,
overheadTime = overheadTime
)
}

private fun createJUnitTestCase(
testCase: TestCase,
toolResultsStep: ToolResultsStep
toolResultsStep: ToolResultsStep,
overheadTime: Double
): JUnitTestCase {
val stackTraces = mapOf(
testCase.status to testCase.stackTraces?.map(StackTrace::getException)
)
return JUnitTestCase(
name = testCase.testCaseReference.name,
classname = testCase.testCaseReference.className,
time = testCase.elapsedTime.format(),
time = (testCase.elapsedTime.millis() + overheadTime).format(),
failures = stackTraces["failed"],
errors = stackTraces["error"],
// skipped = true is represented by null. skipped = false is "absent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,18 @@ package ftl.reports.api
import com.google.api.services.toolresults.model.Step
import ftl.reports.api.data.TestExecutionData
import ftl.reports.api.data.TestSuiteOverviewData
import ftl.reports.xml.model.JUnitTestCase
import ftl.reports.xml.model.JUnitTestSuite

internal fun List<TestExecutionData>.createJUnitTestSuites() = map { data: TestExecutionData ->
createJUnitTestSuite(
data = data,
overview = data.createTestSuitOverviewData(),
testCases = createJUnitTestCases(
testCases = data.testCases,
toolResultsStep = data.testExecution.toolResultsStep
)
overview = data.createTestSuitOverviewData()
)
}

private fun createJUnitTestSuite(
data: TestExecutionData,
overview: TestSuiteOverviewData,
testCases: List<JUnitTestCase>
overview: TestSuiteOverviewData
) = JUnitTestSuite(
name = data.step.testSuiteName(),
timestamp = data.timestamp.asUnixTimestamp().formatUtcDate(),
Expand All @@ -29,15 +23,15 @@ private fun createJUnitTestSuite(
errors = overview.errors.toString(),
skipped = overview.skipped.toString(),
flakes = overview.flakes,
testcases = testCases.toMutableList(),
time = testCases.sumTime().format() // FIXME include also setup and teardown duration https://github.com/Flank/flank/issues/557
testcases = createJUnitTestCases(
testCases = data.testCases,
toolResultsStep = data.testExecution.toolResultsStep,
overheadTime = overview.overheadTime
).toMutableList(),
time = overview.elapsedTime.format()
)

private fun Step.testSuiteName(): String {
val map = dimensionValue.map { it.key to it.value }.toMap()
return listOf(map["Model"], map["Version"], map["Locale"], map["Orientation"]).joinToString("-")
}

private fun List<JUnitTestCase>.sumTime(): Double = this
.map { it.time?.toDouble() ?: 0.0 }
.reduce { acc, d -> acc + d }
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
package ftl.reports.api

import com.google.api.services.toolresults.model.TestCase
import com.google.api.services.toolresults.model.TestSuiteOverview
import ftl.reports.api.data.TestExecutionData
import ftl.reports.api.data.TestSuiteOverviewData

internal fun TestExecutionData.createTestSuitOverviewData(): TestSuiteOverviewData {
val skipped = step.testExecutionStep.testSuiteOverviews.first().skippedCount ?: 0
val overview: TestSuiteOverview = step.testExecutionStep.testSuiteOverviews.first()
val skipped: Int = overview.skippedCount ?: 0
return TestSuiteOverviewData(
total = testCases.size + skipped,
errors = testCases.countErrors(),
failures = testCases.countFailures(),
flakes = testCases.countFlakes(),
skipped = skipped
skipped = skipped,
elapsedTime = overview.elapsedTime.millis(),
overheadTime = getOverheadTime(overview, testCases)
)
}

private fun List<TestCase>.countErrors() = count { !it.flaky && it.status == "error" }
private fun List<TestCase>.countFailures() = count { !it.flaky && it.status == "failed" }
private fun List<TestCase>.countFlakes() = count { it.flaky }

private fun getOverheadTime(
overview: TestSuiteOverview,
testCases: List<TestCase>
) = if (testCases.isEmpty())
0.0 else
(overview.elapsedTime.millis() - testCases.sumTime()) / testCases.size

private fun List<TestCase>.sumTime(): Double = sumByDouble { it.elapsedTime.millis() }
6 changes: 3 additions & 3 deletions test_runner/src/main/kotlin/ftl/reports/api/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ internal fun Double.format(): String = "%.3f".format(Locale.ROOT, this)

internal fun Int?.format() = (this ?: 0).toString()

internal fun Duration?.format(): String =
internal fun Duration?.millis(): Double =
if (this == null)
"0.0" else
((seconds ?: 0) + nanosToSeconds(nanos)).format()
0.0 else
((seconds ?: 0) + nanosToSeconds(nanos))

// manually divide to keep fractional precision
private fun nanosToSeconds(nanos: Int?): Double =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ data class TestSuiteOverviewData(
val errors: Int,
val failures: Int,
val flakes: Int,
val skipped: Int
val skipped: Int,
val elapsedTime: Double,
val overheadTime: Double
)
20 changes: 11 additions & 9 deletions test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ object ReportManager {
return matchResult?.groupValues?.last().orEmpty()
}

private fun processXmlFromFile(matrices: MatrixMap, args: IArgs, process: (file: File) -> JUnitTestResult): JUnitTestResult? {
private fun processXmlFromFile(
matrices: MatrixMap,
args: IArgs,
process: (file: File) -> JUnitTestResult
): JUnitTestResult? {
var mergedXml: JUnitTestResult? = null

findXmlFiles(matrices, args).forEach { xmlFile ->
Expand Down Expand Up @@ -132,13 +136,11 @@ object ReportManager {
newResult: JUnitTestResult,
args: IArgs,
testShardChunks: ShardChunks
):
List<ShardEfficiency> {
): List<ShardEfficiency> {
val oldDurations = Shard.createTestMethodDurationMap(oldResult, args)
val newDurations = Shard.createTestMethodDurationMap(newResult, args)

val timeList = mutableListOf<ShardEfficiency>()
testShardChunks.forEachIndexed { index, testSuite ->
return testShardChunks.mapIndexed { index, testSuite ->

var expectedTime = 0.0
var finalTime = 0.0
Expand All @@ -148,10 +150,8 @@ object ReportManager {
}

val timeDiff = (finalTime - expectedTime)
timeList.add(ShardEfficiency("Shard $index", expectedTime, finalTime, timeDiff))
ShardEfficiency("Shard $index", expectedTime, finalTime, timeDiff)
}

return timeList
}

private fun printActual(
Expand All @@ -176,7 +176,9 @@ object ReportManager {

val oldTestResult = GcStorage.downloadJunitXml(args)

newTestResult.mergeTestTimes(oldTestResult)
if (args.useLegacyJUnitResult) {
newTestResult.mergeTestTimes(oldTestResult)
Copy link
Contributor Author

@jan-goral jan-goral Mar 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided to omit this call when not useLegacyJUnitResult cause new junit result (from api) does not favor success over failure nor error, so we don't need to override failed test cases times.

}

if (oldTestResult != null) {
printActual(oldTestResult, newTestResult, args, testShardChunks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,34 +48,34 @@ class CreateJUnitTestCaseKtTest {
JUnitTestCase(
name = "test1",
classname = "TestClassName",
time = "1.100"
time = "2.200"
),
JUnitTestCase(
name = "test2",
classname = "TestClassName",
time = "1.100",
time = "2.200",
skipped = null
),
JUnitTestCase(
name = "test3",
classname = "TestClassName",
time = "1.100",
time = "2.200",
errors = listOf("exception")
).apply {
webLink = "https://console.firebase.google.com/project/projectId/testlab/histories/historyId/matrices/executionId/executions/stepId/testcases/test3"
},
JUnitTestCase(
name = "test4",
classname = "TestClassName",
time = "1.100",
time = "2.200",
failures = listOf("exception")
).apply {
webLink = "https://console.firebase.google.com/project/projectId/testlab/histories/historyId/matrices/executionId/executions/stepId/testcases/test4"
},
JUnitTestCase(
name = "test5",
classname = "TestClassName",
time = "1.100",
time = "2.200",
failures = listOf("exception")
).apply {
webLink = "https://console.firebase.google.com/project/projectId/testlab/histories/historyId/matrices/executionId/executions/stepId/testcases/test5"
Expand All @@ -85,7 +85,8 @@ class CreateJUnitTestCaseKtTest {

val actual = createJUnitTestCases(
testCases = testCases,
toolResultsStep = toolResultsStep
toolResultsStep = toolResultsStep,
overheadTime = 1.1
)

// then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ class CreateJUnitTestSuiteKtTest {
// given
every {
any<TestExecutionData>().createTestSuitOverviewData()
} returns TestSuiteOverviewData(1, 1, 1, 1, 1)
} returns TestSuiteOverviewData(1, 1, 1, 1, 1, 1.1, 1.1)

val jUnitTestCase = JUnitTestCase(null, null, "1.1")

every {
createJUnitTestCases(any(), any())
createJUnitTestCases(any(), any(), any())
} returns listOf(jUnitTestCase)

val testExecutionDataList = listOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ftl.reports.api

import com.google.api.services.testing.model.TestExecution
import com.google.api.services.toolresults.model.Duration
import com.google.api.services.toolresults.model.Step
import com.google.api.services.toolresults.model.TestCase
import com.google.api.services.toolresults.model.TestExecutionStep
Expand All @@ -24,12 +25,21 @@ class CreateTestSuitOverviewDataKtTest {
TestCase().apply { status = "error" },
TestCase().apply { status = "failed" },
TestCase().apply { flaky = true }
),
).apply {
forEach {
it.elapsedTime = Duration().apply {
seconds = 1
}
}
},
step = Step().apply {
testExecutionStep = TestExecutionStep().apply {
testSuiteOverviews = listOf(
TestSuiteOverview().apply {
skippedCount = 1
elapsedTime = Duration().apply {
seconds = 8
}
}
)
}
Expand All @@ -42,7 +52,9 @@ class CreateTestSuitOverviewDataKtTest {
errors = 1,
failures = 1,
skipped = 1,
flakes = 1
flakes = 1,
elapsedTime = 8.0,
overheadTime = 1.0
)
val actual = testExecutionData.createTestSuitOverviewData()

Expand Down