-
Notifications
You must be signed in to change notification settings - Fork 119
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
Added printing outcome details #862
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
195efa7
#829 Added printing outcome details
957bcfc
#829 update tests
a6e0a39
#829 update release_notes.md
0cc62e3
#829 fix OutcomeDetailsFormatter.kt
8d3335e
#829 Fixing pr comments
943c48f
#829 Handle unknown failure
9c170d2
Simplify
jan-goral 2d2d8a8
Fix test
jan-goral 4e0e266
Add plant uml diagram for results_summary.py
jan-goral 2fadd9d
Move OutcomeDetailsFormatter.kt to same packet as SavedMatrix.kt
jan-goral 8102b71
Fix
jan-goral 1949804
#829 Display outcome details based on shards sum
e513201
Add summary_output.md doc
jan-goral ccbbe90
#829 Show robo test information
5ba7230
#829 Fixed flaky outcome
418e1f9
#829 Fixed tests and change flaky outcome logic
3ca25de
Fix total count
jan-goral d6e49ac
Fix total count test
jan-goral 1d58a1a
#829 small refactor
45b4629
#829 PR fixes
d911dc5
#829 PR fixes
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
@startuml | ||
start | ||
:CreateMatrixOutcomeSummaryUsingSteps; | ||
:_GetStepOutcomeDetails; | ||
if (outcome success) then (yes) | ||
:_GetSuccessCountDetails; | ||
if (successDetail and otherNativeCrash) then (yes) | ||
:format details; | ||
else (no) | ||
:details; | ||
endif | ||
else if (failure) then (yes) | ||
if (failureDetail) then (yes) | ||
:_GetFailureDetail; | ||
elseif (not testExecutionStep) then (yes) | ||
:Unknown failure; | ||
else (no) | ||
:_GetFailureOrFlakyCountDetails; | ||
endif | ||
else if (inconclusive) then (yes) | ||
:_GetInconclusiveDetail; | ||
elseif (skipped) then (yes) | ||
:_GetSkippedDetail; | ||
else (no) | ||
:Unknown outcome; | ||
endif | ||
end | ||
|
||
start | ||
:CreateMatrixOutcomeSummaryUsingEnvironments; | ||
if (environments and all environmentResult outcome) then (yes) | ||
:_GetEnvironmentOutcomeDetails; | ||
if (outcome success) then (yes) | ||
:_GetSuccessCountDetails; | ||
if (successDetail and otherNativeCrash) then (yes) | ||
:format details; | ||
else (no) | ||
:details; | ||
endif | ||
else if (failure or flaky) then (yes) | ||
if (failureDetail) then (yes) | ||
:_GetFailureDetail; | ||
else (no) | ||
:_GetFailureOrFlakyCountDetails; | ||
endif | ||
else if (inconclusive) then (yes) | ||
:_GetInconclusiveDetail; | ||
elseif (skipped) then (yes) | ||
:_GetSkippedDetail; | ||
else (no) | ||
:Unknown outcome; | ||
endif | ||
else (no) | ||
:_GetStepOutcomeDetails; | ||
endif | ||
end | ||
@enduml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Formatted summary output | ||
``` | ||
┌─────────┬──────────────────────┬─────────────────────┐ | ||
│ OUTCOME │ MATRIX ID │ TEST DETAILS │ | ||
├─────────┼──────────────────────┼─────────────────────┤ | ||
│ success │ matrix-1z85qtvdnvb0l │ 4 test cases passed │ | ||
└─────────┴──────────────────────┴─────────────────────┘ | ||
``` | ||
|
||
|
||
## User scenario | ||
As a user I want to see finely formatted summary result at the end of execution output. | ||
|
||
## Motivation | ||
Gcloud prints summary output in the table. It looks nice and is readable. Why we wouldn't have same in flank? | ||
|
||
## Possible outputs | ||
Numbers are representing `OUTCOME` column, points are representing `TEST DETAILS` column. | ||
1. `success | flaky` | ||
* `${1} test cases passed | ${2} skipped | ${3} flakes | (Native crash) | ---` | ||
2. `failure` | ||
* `${1} test cases failed | ${2} errors | ${3} passed | ${4} skipped | ${4} flakes | (Native crash)` | ||
* `Application crashed | (Native crash)` | ||
* `Test timed out | (Native crash)` | ||
* `App failed to install | (Native crash)` | ||
* `Unknown failure | (Native crash)` | ||
3. `inconclusive` | ||
* `Infrastructure failure` | ||
* `Test run aborted by user` | ||
* `Unknown reason` | ||
4. `skipped` | ||
* `Incompatible device/OS combination` | ||
* `App does not support the device architecture` | ||
* `App does not support the OS version` | ||
* `Unknown reason` | ||
|
||
## Implementation details | ||
|
||
### Outcome calculation | ||
It should be mentioned there are some crucial differences how flank and gcloud calculates outcome value. | ||
|
||
Gcloud is using following API calls | ||
1. `self._client.projects_histories_executions_environments.List(request)` | ||
2. `self._client.projects_histories_executions_steps.List(request)` | ||
|
||
The first one is default, but if returns any `environment` without `environmentResult.outcome`, the second one will be used to obtain `steps`. | ||
Both `environemnts` and `steps` can provide `outcome`. The difference between them is the `steps` returns `success` event if tests are `flaky`. | ||
Currently, we don't know why `self._client.projects_histories_executions_environments.List(request)` may return empty `environmentResult.outcome`. | ||
|
||
In difference to gcloud flank uses 3 api call to obtain necessary data | ||
1. `TestMatrix` - `GcTesting.get.projects().testMatrices().get(projectId, testMatrixId)` | ||
2. `Step` - `toolsResults.projects().histories().executions().steps().get(projectId, historyId, executionId, stepId)` | ||
3. `ListTestCasesResponse` - `toolsResults.projects().histories().executions().steps().testCases().get(projectId, historyId, executionId, stepId)` | ||
|
||
`TestMatrix` from first call provides `ToolResultsStep` through `TestExecution` which is used to obtain arguments for next two calls. | ||
|
||
This is part of flank legacy. Those api calls provides data for `JUnitResult`. | ||
As `JUnitResult` contains all data required to generate `table` output, we can reuse it. | ||
In result, we are forced to calculate `flaky` outcomes on flank site because of `step`. | ||
Probably it is place for little improvement in the future. | ||
|
||
### Test details calculation | ||
When flank and gcloud implementations can be slightly different because of programming languages, | ||
the logic behind is the mainly same. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
test_runner/src/main/kotlin/ftl/json/OutcomeDetailsFormatter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package ftl.json | ||
|
||
import com.google.api.services.toolresults.model.FailureDetail | ||
import com.google.api.services.toolresults.model.InconclusiveDetail | ||
import com.google.api.services.toolresults.model.Outcome | ||
import com.google.api.services.toolresults.model.SkippedDetail | ||
import ftl.reports.api.data.TestSuiteOverviewData | ||
import ftl.util.StepOutcome.failure | ||
import ftl.util.StepOutcome.flaky | ||
import ftl.util.StepOutcome.inconclusive | ||
import ftl.util.StepOutcome.skipped | ||
import ftl.util.StepOutcome.success | ||
import ftl.util.StepOutcome.unset | ||
|
||
fun Outcome.getDetails(testSuiteOverviewData: TestSuiteOverviewData?) = when (summary) { | ||
success, flaky -> testSuiteOverviewData?.getSuccessOutcomeDetails(successDetail?.otherNativeCrash ?: false) | ||
failure -> failureDetail.getFailureOutcomeDetails(testSuiteOverviewData) | ||
inconclusive -> inconclusiveDetail.formatOutcomeDetails() | ||
skipped -> skippedDetail.formatOutcomeDetails() | ||
unset -> "Unset outcome" | ||
else -> "Unknown outcome" | ||
} | ||
|
||
private fun TestSuiteOverviewData.getSuccessOutcomeDetails( | ||
otherNativeCrash: Boolean | ||
) = StringBuilder("$successCount test cases passed").apply { | ||
if (skipped > 0) append(skippedMessage(skipped)) | ||
if (flakes > 0) append(flakesMessage(flakes)) | ||
if (otherNativeCrash) append(NATIVE_CRASH_MESSAGE) | ||
}.toString() | ||
|
||
private val TestSuiteOverviewData.successCount | ||
get() = total - errors - failures - skipped - flakes | ||
|
||
private fun FailureDetail?.getFailureOutcomeDetails(testSuiteOverviewData: TestSuiteOverviewData?) = when { | ||
piotradamczyk5 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this == null -> testSuiteOverviewData?.buildFailureOutcomeDetailsSummary() ?: "Unknown failure" | ||
crashed == true -> "Application crashed" | ||
timedOut == true -> "Test timed out" | ||
notInstalled == true -> "App failed to install" | ||
else -> testSuiteOverviewData?.buildFailureOutcomeDetailsSummary() ?: "Unknown failure" | ||
} + this?.takeIf { it.otherNativeCrash }?.let { NATIVE_CRASH_MESSAGE }.orEmpty() | ||
|
||
private fun TestSuiteOverviewData.buildFailureOutcomeDetailsSummary() = | ||
StringBuilder("$failures test cases failed").apply { | ||
if (errors > 0) append(errorMessage(errors)) | ||
successCount.takeIf { it > 0 }?.let { append(successMessage(it)) } | ||
if (skipped > 0) append(skippedMessage(skipped)) | ||
if (flakes > 0) append(flakesMessage(flakes)) | ||
}.toString() | ||
|
||
private fun InconclusiveDetail?.formatOutcomeDetails() = when { | ||
this == null -> "Unknown reason" | ||
infrastructureFailure == true -> "Infrastructure failure" | ||
abortedByUser == true -> "Test run aborted by user" | ||
else -> "Unknown reason" | ||
} | ||
|
||
private fun SkippedDetail?.formatOutcomeDetails(): String = when { | ||
this == null -> "Unknown reason" | ||
incompatibleDevice == true -> "Incompatible device/OS combination" | ||
incompatibleArchitecture == true -> "App does not support the device architecture" | ||
incompatibleAppVersion == true -> "App does not support the OS version" | ||
else -> "Unknown reason" | ||
} | ||
|
||
private const val NATIVE_CRASH_MESSAGE = " (Native crash)" | ||
private val flakesMessage: (Int) -> String = { ", $it flaky" } | ||
private val skippedMessage: (Int) -> String = { ", $it skipped" } | ||
private val successMessage: (Int) -> String = { ", $it passed" } | ||
private val errorMessage: (Int) -> String = { ", $it errors" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.