Skip to content
Open
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
5 changes: 5 additions & 0 deletions config/openshift-customizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ releases:
periodic-ci-Azure-ARO-HCP-main-periodic-prod-uksouth-e2e-parallel: true
periodic-ci-Azure-ARO-HCP-main-periodic-prod-e2e-parallel-ocp-nightly: true
rosa-stage:
overview:
multiVersionInstallTests: true
recentFailuresPeriod: "48h"
recentFailuresPreviousPeriod: "168h"
topFailingTestsPeriod: "168h"
jobs:
# ROSA Classic/STS nightly (stage)
periodic-ci-openshift-osde2e-main-nightly-4.16-rosa-classic-sts: true
Expand Down
5 changes: 5 additions & 0 deletions config/openshift.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17064,6 +17064,11 @@ releases:
rosa-integration: {}
rosa-production: {}
rosa-stage:
overview:
multiVersionInstallTests: true
recentFailuresPeriod: 48h
recentFailuresPreviousPeriod: 168h
topFailingTestsPeriod: 168h
jobs:
periodic-ci-openshift-osde2e-main-aws-stage-informing-default: true
periodic-ci-openshift-osde2e-main-nightly-4.16-osd-aws: true
Expand Down
40 changes: 37 additions & 3 deletions pkg/api/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
log "github.com/sirupsen/logrus"

apitype "github.com/openshift/sippy/pkg/apis/api"
configv1 "github.com/openshift/sippy/pkg/apis/config/v1"
sippyprocessingv1 "github.com/openshift/sippy/pkg/apis/sippyprocessing/v1"
"github.com/openshift/sippy/pkg/db"
"github.com/openshift/sippy/pkg/db/query"
Expand Down Expand Up @@ -44,7 +45,7 @@ func useNewInstallTest(release string) bool {

// PrintOverallReleaseHealthFromDB gives a summarized status of the overall health, including
// infrastructure, install, upgrade, and variant success rates.
func PrintOverallReleaseHealthFromDB(w http.ResponseWriter, dbc *db.DB, release string, reportEnd time.Time) {
func PrintOverallReleaseHealthFromDB(w http.ResponseWriter, dbc *db.DB, release string, reportEnd time.Time, overviewCfg *configv1.OverviewConfig) {
excludedVariants := testidentification.DefaultExcludedVariants
// Minor upgrades install a previous version and should not be counted against the current version's install stat.
excludedInstallVariants := testidentification.DefaultExcludedVariants
Expand Down Expand Up @@ -74,6 +75,30 @@ func PrintOverallReleaseHealthFromDB(w http.ResponseWriter, dbc *db.DB, release
if installIndicator, found := query.TestReportExcludeVariants(dbc, release, installTestName, excludedInstallVariants); found {
indicators["install"] = installIndicator
}

// Releases spanning OCP version boundaries (e.g. rosa-stage) may have jobs
// producing old-style synthetic tests ([sig-sippy] install should work) and
// jobs producing new-style tests (install should succeed: overall). Query
// the alternate name set and keep whichever indicator has more CurrentRuns
// so the overview cards use the most-populated metric.
if overviewCfg != nil && overviewCfg.MultiVersionInstallTests {
altInfra := testidentification.NewInfrastructureTestName
altInstall := testidentification.NewInstallTestName
if useNewInstallTest(release) {
altInfra = testidentification.InfrastructureTestName
altInstall = testidentification.InstallTestName
}
if altInfraIndicator, found := query.TestReportExcludeVariants(dbc, release, altInfra, excludedVariants); found {
if existing, exists := indicators["infrastructure"]; !exists || altInfraIndicator.CurrentRuns > existing.CurrentRuns {
indicators["infrastructure"] = altInfraIndicator
}
}
if altInstallIndicator, found := query.TestReportExcludeVariants(dbc, release, altInstall, excludedInstallVariants); found {
if existing, exists := indicators["install"]; !exists || altInstallIndicator.CurrentRuns > existing.CurrentRuns {
indicators["install"] = altInstallIndicator
}
}
}
if upgradeIndicator, found := query.TestReportExcludeVariants(dbc, release, testidentification.UpgradeTestName, excludedVariants); found {
indicators["upgrade"] = upgradeIndicator
}
Expand Down Expand Up @@ -114,13 +139,22 @@ func PrintOverallReleaseHealthFromDB(w http.ResponseWriter, dbc *db.DB, release
// TODO: use or remove this logic
var warnings []string

RespondWithJSON(http.StatusOK, w, apitype.Health{
health := apitype.Health{
Indicators: indicators,
LastUpdated: lastUpdated,
Current: currStats,
Previous: prevStats,
Warnings: warnings,
})
}
if overviewCfg != nil {
health.Overview = &apitype.OverviewConfig{
MultiVersionInstallTests: overviewCfg.MultiVersionInstallTests,
RecentFailuresPeriod: overviewCfg.RecentFailuresPeriod,
RecentFailuresPreviousPeriod: overviewCfg.RecentFailuresPreviousPeriod,
TopFailingTestsPeriod: overviewCfg.TopFailingTestsPeriod,
}
}
RespondWithJSON(http.StatusOK, w, health)
}

func calculateJobResultStatistics(results []apitype.Job) (currStats, prevStats sippyprocessingv1.Statistics) {
Expand Down
31 changes: 31 additions & 0 deletions pkg/api/health_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package api

import (
"testing"
)

func TestUseNewInstallTest(t *testing.T) {
tests := []struct {
release string
expected bool
}{
{"4.17", true},
{"4.11", true},
{"4.10", false},
{"4.8", false},
{"3.11", false},
{"5.0", true},
// Non-numeric releases return false (use old synthetic names)
{"rosa-stage", false},
{"aro-stage", false},
{"Presubmits", false},
}

for _, tt := range tests {
t.Run(tt.release, func(t *testing.T) {
if got := useNewInstallTest(tt.release); got != tt.expected {
t.Errorf("useNewInstallTest(%q) = %v, want %v", tt.release, got, tt.expected)
}
})
}
}
9 changes: 9 additions & 0 deletions pkg/apis/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,15 @@ type Health struct {
Warnings []string `json:"warnings"`
Current v1.Statistics `json:"current_statistics"`
Previous v1.Statistics `json:"previous_statistics"`
Overview *OverviewConfig `json:"overview,omitempty"`
}

// OverviewConfig is passed to the frontend to customize release overview rendering.
type OverviewConfig struct {
MultiVersionInstallTests bool `json:"multi_version_install_tests,omitempty"`
RecentFailuresPeriod string `json:"recent_failures_period,omitempty"`
RecentFailuresPreviousPeriod string `json:"recent_failures_previous_period,omitempty"`
TopFailingTestsPeriod string `json:"top_failing_tests_period,omitempty"`
}

type ProwJobRunRiskAnalysis struct {
Expand Down
23 changes: 23 additions & 0 deletions pkg/apis/config/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ type ReleaseConfig struct {

// InformingJobs is the list of informing payload jobs
InformingJobs []string `yaml:"informingJobs,omitempty"`

// Overview configures the release overview page display behavior.
Overview *OverviewConfig `yaml:"overview,omitempty"`
}

// OverviewConfig controls how the release overview page is rendered.
type OverviewConfig struct {
// MultiVersionInstallTests queries both old-style synthetic and new-style
// install test names, keeping whichever has more data. Useful for releases
// that span multiple OCP versions.
MultiVersionInstallTests bool `yaml:"multiVersionInstallTests,omitempty" json:"multi_version_install_tests,omitempty"`

// RecentFailuresPeriod overrides the default "current" window for new test
// failure detection (default: "24h").
RecentFailuresPeriod string `yaml:"recentFailuresPeriod,omitempty" json:"recent_failures_period,omitempty"`

// RecentFailuresPreviousPeriod overrides the default "previous" window for
// new test failure comparison (default: "72h").
RecentFailuresPreviousPeriod string `yaml:"recentFailuresPreviousPeriod,omitempty" json:"recent_failures_previous_period,omitempty"`

// TopFailingTestsPeriod, when set, adds a "Top Failing Tests" section
// showing all test failures within this window (e.g. "168h").
TopFailingTestsPeriod string `yaml:"topFailingTestsPeriod,omitempty" json:"top_failing_tests_period,omitempty"`
}

type ComponentReadinessConfig struct {
Expand Down
9 changes: 7 additions & 2 deletions pkg/sippyserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1224,9 +1224,14 @@ func (s *Server) jsonTestLifecyclesFromDB(w http.ResponseWriter, req *http.Reque

func (s *Server) jsonHealthReportFromDB(w http.ResponseWriter, req *http.Request) {
release := s.getParamOrFail(w, req, "release")
if release != "" {
api.PrintOverallReleaseHealthFromDB(w, s.db, release, s.GetReportEnd())
if release == "" {
return
}
var overviewCfg *v1.OverviewConfig
if cfg, ok := s.config.Releases[release]; ok {
overviewCfg = cfg.Overview
}
api.PrintOverallReleaseHealthFromDB(w, s.db, release, s.GetReportEnd(), overviewCfg)
}

func (s *Server) jsonBuildClusterHealth(w http.ResponseWriter, req *http.Request) {
Expand Down
22 changes: 16 additions & 6 deletions sippy-ng/src/releases/RecentTestFailures.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ export default function RecentTestFailures(props) {
const [rowsPerPage, setRowsPerPage] = React.useState(props.limit || 5)

const period = props.period || '24h'
const previousPeriod = props.previousPeriod || '72h'
const previousPeriod =
props.previousPeriod !== undefined ? props.previousPeriod : '72h'
const includeOutputs =
props.includeOutputs !== undefined ? props.includeOutputs : true

Expand All @@ -369,7 +370,9 @@ export default function RecentTestFailures(props) {
'/api/tests/recent_failures' +
`?release=${safeEncodeURIComponent(props.release)}` +
`&period=${safeEncodeURIComponent(period)}` +
`&previousPeriod=${safeEncodeURIComponent(previousPeriod)}` +
(previousPeriod
? `&previousPeriod=${safeEncodeURIComponent(previousPeriod)}`
: '') +
`&includeOutputs=${includeOutputs}` +
`&sortField=${safeEncodeURIComponent(orderBy)}` +
`&sort=${safeEncodeURIComponent(order)}` +
Expand Down Expand Up @@ -427,7 +430,11 @@ export default function RecentTestFailures(props) {
{title}
</Typography>
<Tooltip
title={`Tests that failed in the last ${period} but did not fail in the ${previousPeriod} before that. This helps surface new regressions.`}
title={
previousPeriod
? `Tests that failed in the last ${period} but did not fail in the ${previousPeriod} before that. This helps surface new regressions.`
: `All tests that failed in the last ${period}.`
}
>
<InfoIcon className={classes.infoIcon} />
</Tooltip>
Expand Down Expand Up @@ -456,11 +463,14 @@ export default function RecentTestFailures(props) {
<Box className={classes.emptyState}>
<ExpandMoreIcon className={classes.emptyIcon} />
<Typography variant="body1" color="text.secondary">
No new test failures detected
{previousPeriod
? 'No new test failures detected'
: 'No test failures detected'}
</Typography>
<Typography variant="caption" color="text.secondary">
No tests started failing in the last {period} that were not already
failing in the prior {previousPeriod}.
{previousPeriod
? `No tests started failing in the last ${period} that were not already failing in the prior ${previousPeriod}.`
: `No tests failed in the last ${period}.`}
</Typography>
</Box>
) : (
Expand Down
20 changes: 19 additions & 1 deletion sippy-ng/src/releases/ReleaseOverview.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,27 @@ export default function ReleaseOverview(props) {
/>

<Grid item xs={12}>
<RecentTestFailures release={props.release} />
<RecentTestFailures
release={props.release}
period={data.overview?.recent_failures_period || '24h'}
previousPeriod={
data.overview?.recent_failures_previous_period || '72h'
}
/>
</Grid>

{data.overview?.top_failing_tests_period && (
<Grid item xs={12}>
<RecentTestFailures
release={props.release}
title={`Top Failing Tests (${data.overview.top_failing_tests_period})`}
period={data.overview.top_failing_tests_period}
previousPeriod={null}
limit={10}
/>
</Grid>
)}

{releases?.release_attrs?.[props.release]?.capabilities
?.payloadTags && (
<Grid item xs={12}>
Expand Down