Files
tasks/tools/flakereport/writer.go
Stephan BehnkeandGitHub 40be0f40c8 Fix Crash and CI Breakers reporting (#9478)
## What changed?

Fixed Crash and CI Breakers reporting in flakereport.

## Why?

Misleading aggregation.

## How did you test it?

```
go run ./cmd/tools/flakereport generate --days 7 --output-dir out
```

<details><summary>GitHub (abridged)</summary>
<p>

### Crashes

| Test | Crash Rate | Last Failure | Links |
|------|------------|-------------|-------|
| `unit-test` | 4.0% (1/25) | 3h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22966733319)
[2](https://github.com/temporalio/temporal/actions/runs/22923165266) |
| `functional-test` | 3.5% (35/1003) | 1h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22970016748/job/66684243853)
[2](https://github.com/temporalio/temporal/actions/runs/22970016748/job/66684243820)
[3](https://github.com/temporalio/temporal/actions/runs/22969997600/job/66684218138)
|


### CI Breakers (Failed All Retries)

| Test | CI Break Rate | Last Failure | Links |
|------|------------|-------------|-------|
|
`TestNexusStateReplicationTestSuite/EnableTransitionHistory/TestNexusCallbackReplicated`
| **50.0% (13/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674252859)
[2](https://github.com/temporalio/temporal/actions/runs/22931602170/job/66576965326)
[3](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593587)
|
|
`TestFuncClustersTestSuite/DisableTransitionHistory/TestForceMigration_ClosedWorkflow`
| **30.8% (8/26)** | 1h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923524988/job/66528148344)
[2](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396416)
[3](https://github.com/temporalio/temporal/actions/runs/22929738731/job/66548562937)
|
|
`TestFuncClustersTestSuite/DisableTransitionHistory/TestForceMigration_ResetWorkflow`
| **19.2% (5/26)** | 19h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22928356811/job/66544280229)
[2](https://github.com/temporalio/temporal/actions/runs/22923524988/job/66528148344)
[3](https://github.com/temporalio/temporal/actions/runs/22929738731/job/66548562947)
|
|
`TestFuncClustersTestSuite/EnableTransitionHistory/TestForceMigration_ClosedWorkflow`
| **19.2% (5/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674252859)
[2](https://github.com/temporalio/temporal/actions/runs/22931602170/job/66576965326)
[3](https://github.com/temporalio/temporal/actions/runs/22929738731/job/66548563003)
|
|
`TestFuncClustersTestSuite/EnableTransitionHistory/TestForceMigration_ResetWorkflow`
| **15.4% (4/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22928356811/job/66544280299)
[2](https://github.com/temporalio/temporal/actions/runs/22941944027/job/66585445737)
[3](https://github.com/temporalio/temporal/actions/runs/22926291741/job/66537603391)
|
|
`TestDeploymentVersionSuiteV2/TestReactivationSignalCache_Deduplication_Reset`
| **11.5% (3/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
[2](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
[3](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
| `TestScheduleFunctionalSuite/TestListSchedulesReturnsWorkflowStatus` |
**7.7% (2/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
[2](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
| `TestWorkerDeploymentSuiteV2/TestSetCurrentVersion_Batching` | **7.7%
(2/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
[2](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
| `TestClientDataConverterTestSuite` | **7.7% (2/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
[2](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
|
`TestVersioning3FunctionalSuiteV0/TestTransitionDuringTransientTask_WithSignal`
| **7.7% (2/26)** | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967653083/job/66676176237)
[2](https://github.com/temporalio/temporal/actions/runs/22967653083/job/66676176283)
|
|
`TestWorkerDeploymentSuiteV2/TestResourceExhaustedErrors_Converted_To_ReadableMessage`
| **7.7% (2/26)** | 19h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
[2](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
|
|
`TestDeploymentVersionSuiteV0/TestVersionMissingTaskQueues_ValidSetCurrentVersion`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestVersioning3FunctionalSuiteV2/TestPinnedCaN_UpgradeOnCaN_NormalWFT_PinnedOverride_WithSuggest/ForceTaskForwardNoPollForwardAllowSync`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestVersioning3FunctionalSuiteV0/TestPinnedCaN_UpgradeOnCaN_NormalWFT_WithSuggest/ForceTaskForwardNoPollForwardForceAsync`
| 3.8% (1/26) | 21h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
|
| `TestDeploymentVersionSuiteV2/TestVersionScavenger_DeleteOnAdd` | 3.8%
(1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestVersioning3FunctionalSuiteV2/TestTransitionDuringTransientTask_WithSignal`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
| `TestVersioning3FunctionalSuiteV2/TestVersionedQueueUnload` | 3.8%
(1/26) | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967653083/job/66676176237)
|
| `TestScheduleFunctionalSuite/TestNextTimeCache` | 3.8% (1/26) | 19h
ago |
[1](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
|
|
`TestVersioningFunctionalSuite/TestDispatchActivityFail/NoTaskForwardForcePollForwardForceAsync`
| 3.8% (1/26) | 23h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
|
| `TestPrioritySuite/TestSubqueue_Migration` | 3.8% (1/26) | 21h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
|
|
`TestAdvancedVisibilitySuite/TestWorkerTaskReachability_Unversioned_InTaskQueue`
| 3.8% (1/26) | 21h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
|
| `TestDeploymentVersionSuiteV2/TestDeleteVersion_DrainingVersion` |
3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestDeploymentVersionSuiteV0/TestStartWorkflowExecution_ReactivateVersionOnPinned_WithConflictPolicy`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestTaskQueueStats_Classic_Suite/TestCurrentAbsorbsUnversionedBacklog_WhenRampingToUnversioned/ForceTaskForwardForcePollForwardAllowSync`
| 3.8% (1/26) | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967653083/job/66676176237)
|
|
`TestWorkflowUpdateSuite/SpeculativeWorkflowTask_QueryFailureClearsWFContext`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestTaskQueueStats_Classic_Suite/TestMultipleTasks_WithMatchingBehavior_ValidateStats/ForceTaskForwardForcePollForwardForceAsync`
| 3.8% (1/26) | 19h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
|
|
`TestTaskQueueStats_Pri_Suite/TestRampingAndCurrentAbsorbUnversionedBacklog/ForceTaskForwardNoPollForwardForceAsync`
| 3.8% (1/26) | 19h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
|
|
`TestVersioningFunctionalSuite/TestDispatchActivityTimeoutCrossTq/NoTaskForwardForcePollForwardAllowSync`
| 3.8% (1/26) | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
| `TestWorkerDeploymentSuiteV0/TestDrainRollbackedVersion` | 3.8% (1/26)
| 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
|
`TestWorkerDeploymentSuiteV0/TestSetWorkerDeploymentRampingVersion_SetRampingAsCurrent`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestStandaloneActivityTestSuite/TestHeartbeat/ActivityRetriesOnHeartbeatTimeout`
| 3.8% (1/26) | 23h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
|
|
`TestTaskQueueStats_Classic_Suite/TestMultipleTasks_WithMatchingBehavior_ValidateStats/NoTaskForwardForcePollForwardForceAsync`
| 3.8% (1/26) | 23h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
|
|
`TestTaskQueueStats_Pri_Suite/TestMultipleTasks_WithMatchingBehavior_ValidateStats/ForceTaskForwardForcePollForwardAllowSync`
| 3.8% (1/26) | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967653083/job/66676176237)
|
|
`TestWorkerDeploymentSuiteV0/TestSetRampingVersion_Concurrent_DifferentVersions_NoUnexpectedErrors`
| 3.8% (1/26) | 19h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
|
|
`TestDeploymentVersionSuiteV0/TestVersionMissingTaskQueues_ValidSetRampingVersion`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestDeploymentVersionSuiteV2/TestVersionIgnoresDrainageSignalWhenCurrentOrRamping`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestVersioning3FunctionalSuiteV0/TestPinnedCaN_UpgradeOnCaN_TransientWFT_WithSuggest/ForceTaskForwardForcePollForwardAllowSync`
| 3.8% (1/26) | 19h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22931281792/job/66553396454)
|
|
`TestStandaloneActivityTestSuite/TestDescribeActivityExecution_DeadlineExceeded/NoCallerDeadline`
| 3.8% (1/26) | 1h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22970016748/job/66684243820)
|
|
`TestAdvancedVisibilitySuiteLegacy/TestUpsertWorkflowExecutionSearchAttributes`
| 3.8% (1/26) | 21h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
|
|
`TestVersioning3FunctionalSuiteV2/TestPinnedCaN_UpgradeOnCaN_NormalWFT_NoSuggest/ForceTaskForwardForcePollForwardForceAsync`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestDeploymentVersionSuiteV0/TestVersionIgnoresDrainageSignalWhenCurrentOrRamping`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestVersioning3FunctionalSuiteV2/TestAutoUpgradeCaN_UpgradeOnCaN/ForceTaskForwardForcePollForwardAllowSync`
| 3.8% (1/26) | 21h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22929090805/job/66546593717)
|
|
`TestDeploymentVersionSuiteV0/TestUpdateWorkflowExecutionOptions_SetImpliedPinnedSuccess`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestDeploymentVersionSuiteV0/TestReactivationSignalCache_Deduplication_StartWorkflow`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestDeploymentVersionSuiteV2/TestVersionMissingTaskQueues_ValidSetRampingVersion`
| 3.8% (1/26) | 28h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22912627598/job/66489344605)
|
|
`TestDeploymentVersionSuiteV0/TestReactivationSignalCache_Deduplication_UpdateOptions`
| 3.8% (1/26) | 122h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22775553239/job/66068056068)
|
|
`TestNexusApiTestSuiteWithTemporalFailures/TestNexusCancelOperation_Outcomes/handler_timeout/ByNamespaceAndTaskQueue`
| 3.8% (1/26) | 23h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
|
|
`TestDeploymentVersionSuiteV0/TestStartWorkflowExecution_ReactivateVersionOnPinned`
| 3.8% (1/26) | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967233794/job/66674253006)
|
| `TestCronTestSuite/TestCronWorkflow` | 3.8% (1/26) | 2h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22967653083/job/66676176283)
|
| `TestWorkerDeploymentSuiteV0/TestDeploymentVersionLimits` | 3.8%
(1/26) | 23h ago |
[1](https://github.com/temporalio/temporal/actions/runs/22923165266/job/66526932600)
|

</p>
</details> 

<details><summary>Slack</summary>
<p>

Flaky Tests Report - Last 7 Days

*CI Success Rate:* 9/26 (34.62%)
*Total Test Runs:* 1134261
*Total Failures:* 3774
*Failure Rate:* 3.33 per 1000 tests

*CI Breakers:* 50
*Crashes:* 2
*Flaky Tests:* 416
*Timeouts:* 0

*CI Breakers (top 10):*
• 50.0% (13/26 runs):
`TestNexusStateReplicationTestSuite/EnableTransitionHistory/TestNexusCallbackReplicated`
• 30.8% (8/26 runs):
`TestFuncClustersTestSuite/DisableTransitionHistory/TestForceMigration_ClosedWorkflow`
• 19.2% (5/26 runs):
`TestFuncClustersTestSuite/DisableTransitionHistory/TestForceMigration_ResetWorkflow`
• 19.2% (5/26 runs):
`TestFuncClustersTestSuite/EnableTransitionHistory/TestForceMigration_ClosedWorkflow`
• 15.4% (4/26 runs):
`TestFuncClustersTestSuite/EnableTransitionHistory/TestForceMigration_ResetWorkflow`
• 11.5% (3/26 runs):
`TestDeploymentVersionSuiteV2/TestReactivationSignalCache_Deduplication_Reset`
• 7.7% (2/26 runs):
`TestWorkerDeploymentSuiteV2/TestResourceExhaustedErrors_Converted_To_ReadableMessage`
• 7.7% (2/26 runs): `TestClientDataConverterTestSuite`
• 7.7% (2/26 runs):
`TestWorkerDeploymentSuiteV2/TestSetCurrentVersion_Batching`
• 7.7% (2/26 runs):
`TestVersioning3FunctionalSuiteV0/TestTransitionDuringTransientTask_WithSignal`

*Flaky Tests (top 10):*
• 100.0% (4 failures): `DATA RACE: Data race detected`
• 100.0% (24 failures): `TestClientDataConverterTestSuite`
• 100.0% (4 failures): `PANIC: Fail in goroutine after
TestWorkerDeploymentSuiteV2/TestConcurrentPollers_DifferentTaskQueues_SameVersion_SetCurrentVersion
has completed — in
TestDeploymentVersionSuiteV2/TestBatchUpdateWorkflowExecutionOptions_SetPinnedThenUnset`
• 100.0% (36 failures): `PANIC: Fail in goroutine after
TestWorkerDeploymentSuiteV2/TestConcurrentPollers_DifferentTaskQueues_SameVersion_SetCurrentVersion
has completed — in
TestWorkerDeploymentSuiteV2/TestConcurrentPollers_DifferentTaskQueues_SameVersion_SetCurrentVersion`
• 100.0% (4 failures): `DATA RACE: Data race detected — in
go.uber.org/zap/zaptest.TestingWriter.Write`
• 49.3% (187 failures):
`TestVersioning3FunctionalSuiteV2/TestTransitionDuringTransientTask_WithoutSignal`
• 48.9% (183 failures):
`TestVersioning3FunctionalSuiteV2/TestTransitionDuringTransientTask_WithSignal`
• 47.5% (161 failures):
`TestVersioning3FunctionalSuiteV0/TestTransitionDuringTransientTask_WithSignal`
• 47.4% (172 failures):
`TestVersioning3FunctionalSuiteV0/TestTransitionDuringTransientTask_WithoutSignal`
• 27.2% (71 failures):
`TestFuncClustersTestSuite/DisableTransitionHistory/TestForceMigration_ClosedWorkflow`


</p>
</details>
2026-03-11 22:24:47 +00:00

136 lines
4.5 KiB
Go

package flakereport
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
"time"
)
// writeFailuresJSON writes failures.json containing every individual test failure (for analytics).
func writeFailuresJSON(outputDir string, failures []TestFailure, repo string) error {
records := make([]FailedTestRecord, 0, len(failures))
for _, f := range failures {
runIDStr := strconv.FormatInt(f.RunID, 10)
records = append(records, FailedTestRecord{
SuiteName: f.SuiteName,
TestName: f.Name,
FailureDate: f.Timestamp.Format(time.RFC3339),
Link: buildGitHubURL(repo, runIDStr, f.JobID),
FailureType: classifyFailure(f.Name),
})
}
data, err := json.MarshalIndent(records, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal failures.json: %w", err)
}
if err := os.WriteFile(filepath.Join(outputDir, "failures.json"), data, 0644); err != nil {
return fmt.Errorf("failed to write failures.json: %w", err)
}
return nil
}
// generateGitHubSummary creates markdown summary for GitHub Actions
func generateGitHubSummary(summary *ReportSummary, runID string, maxLinks int) string {
timestamp := time.Now().Format("2006-01-02 15:04:05")
var content string
content += fmt.Sprintf("## Flaky Tests Report - %s\n\n", timestamp)
// Overall statistics
content += "### Overall Statistics\n\n"
// CI success rate
ciSuccessRate := 0.0
if summary.TotalWorkflowRuns > 0 {
ciSuccessRate = (float64(summary.SuccessfulRuns) / float64(summary.TotalWorkflowRuns)) * 100.0
}
content += fmt.Sprintf("* **CI Success Rate**: %d/%d (%.2f%%)\n", summary.SuccessfulRuns, summary.TotalWorkflowRuns, ciSuccessRate)
content += fmt.Sprintf("* **Total Test Runs**: %d\n", summary.TotalTestRuns)
content += fmt.Sprintf("* **Total Failures**: %d\n", summary.TotalFailures)
content += fmt.Sprintf("* **Overall Failure Rate**: %.1f per 1000 tests\n\n", summary.OverallFailureRate)
// Summary table
content += "### Failure Categories Summary\n\n"
content += "| Category | Unique Tests |\n"
content += "|----------|--------------|\n"
content += fmt.Sprintf("| CI Breakers | %d |\n", len(summary.CIBreakers))
content += fmt.Sprintf("| Crashes | %d |\n", len(summary.Crashes))
content += fmt.Sprintf("| Timeouts | %d |\n", len(summary.Timeouts))
content += fmt.Sprintf("| Flaky Tests | %d |\n\n", summary.TotalFlakyCount)
// CI Breakers section (tests that failed all retries)
if len(summary.CIBreakers) > 0 {
content += "### CI Breakers (Failed All Retries)\n\n"
content += generateTestReportTable(summary.CIBreakers, "CI Break Rate", maxLinks) + "\n"
}
// Crashes section
if len(summary.Crashes) > 0 {
content += "### Crashes\n\n"
content += generateTestReportTable(summary.Crashes, "Crash Rate", maxLinks) + "\n"
}
// Timeouts section
if len(summary.Timeouts) > 0 {
content += "### Timeouts\n\n"
content += generateTestReportTable(summary.Timeouts, "Flake Rate", maxLinks) + "\n"
}
// Flaky tests section (show ALL tests)
if len(summary.FlakyTests) > 0 {
content += "### Flaky Tests\n\n"
content += generateTestReportTable(summary.FlakyTests, "Flake Rate", maxLinks) + "\n"
}
// Flaky suites
if len(summary.Suites) > 0 {
content += "### Flaky Suites\n\n"
content += generateSuiteBreakdownTable(summary.Suites) + "\n"
}
// Link to run
if runID != "" {
content += fmt.Sprintf("\n[View Full Report & Artifacts](https://github.com/%s/actions/runs/%s)\n", defaultRepository, runID)
}
return content
}
// writeGitHubSummary writes markdown summary to GITHUB_STEP_SUMMARY (if set)
// and always writes to outputDir/github-report.md.
func writeGitHubSummary(content string, outputDir string) error {
// Always write to output dir
outPath := filepath.Join(outputDir, "github-report.md")
if err := os.WriteFile(outPath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write github-report.md: %w", err)
}
fmt.Printf("GitHub report written to %s\n", outPath)
// Also write to GITHUB_STEP_SUMMARY if available
summaryFile := os.Getenv("GITHUB_STEP_SUMMARY")
if summaryFile == "" {
return nil
}
file, err := os.OpenFile(summaryFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("failed to open summary file: %w", err)
}
defer func() {
if err := file.Close(); err != nil {
fmt.Printf("Warning: Failed to close summary file: %v\n", err)
}
}()
if _, err := file.WriteString(content); err != nil {
return fmt.Errorf("failed to write summary: %w", err)
}
fmt.Println("GitHub Actions step summary written")
return nil
}