From fcea962d3b0209fc886c19f73011efcb8b69ad8f Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Thu, 20 Aug 2026 21:31:57 +0000 Subject: [PATCH 1/6] TRT-2914: Add IgnoreDisruption filter to PG provider The BigQuery provider excludes tests with the "Disruption" capability when IgnoreDisruption is true, but the PostgreSQL provider had no equivalent filter. This caused BQ and PG to return different test populations for the same request, violating provider parity. Add the disruption exclusion clause to buildDrilldownFilters in the PG query path, matching the BQ semantics. The filter applies to both grid and drill-down queries through the shared outerClause mechanism. Co-Authored-By: Claude Opus 4.6 --- .../dataprovider/postgres/cr_queries.go | 4 + .../dataprovider/postgres/cr_queries_test.go | 91 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries.go index c17f4d0df..6e2597d2a 100644 --- a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries.go +++ b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries.go @@ -96,6 +96,10 @@ func buildDrilldownFilters(reqOptions reqopts.RequestOptions) drilldownFilters { f.outerArgs = append(f.outerArgs, pq.Array(reqOptions.Capabilities)) } + if reqOptions.AdvancedOption.IgnoreDisruption { + f.outerClause += " AND NOT ('Disruption' = ANY(tow.capabilities))" + } + return f } diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go new file mode 100644 index 000000000..fd701c3ab --- /dev/null +++ b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go @@ -0,0 +1,91 @@ +package postgres + +import ( + "strings" + "testing" + + "github.com/openshift/sippy/pkg/apis/api/componentreport/reqopts" +) + +func TestBuildDrilldownFilters(t *testing.T) { + tests := []struct { + name string + reqOptions reqopts.RequestOptions + wantOuterContains string + wantOuterNotContains string + wantOuterArgsCount int + wantInnerClauseNotEmpty bool + }{ + { + name: "empty options produces no clauses", + reqOptions: reqopts.RequestOptions{}, + wantOuterArgsCount: 0, + }, + { + name: "IgnoreDisruption adds disruption exclusion", + reqOptions: reqopts.RequestOptions{ + AdvancedOption: reqopts.Advanced{ + IgnoreDisruption: true, + }, + }, + wantOuterContains: "AND NOT ('Disruption' = ANY(tow.capabilities))", + wantOuterArgsCount: 0, + }, + { + name: "IgnoreDisruption false does not add disruption exclusion", + reqOptions: reqopts.RequestOptions{ + AdvancedOption: reqopts.Advanced{ + IgnoreDisruption: false, + }, + }, + wantOuterNotContains: "Disruption", + wantOuterArgsCount: 0, + }, + { + name: "capabilities filter and IgnoreDisruption combined", + reqOptions: reqopts.RequestOptions{ + TestFilters: reqopts.TestFilters{ + Capabilities: []string{"install"}, + }, + AdvancedOption: reqopts.Advanced{ + IgnoreDisruption: true, + }, + }, + wantOuterContains: "AND NOT ('Disruption' = ANY(tow.capabilities))", + wantOuterArgsCount: 1, + }, + { + name: "single TestIDOption with test ID and capability", + reqOptions: reqopts.RequestOptions{ + TestIDOptions: []reqopts.TestIdentification{ + {TestID: "test-123", Capability: "install"}, + }, + }, + wantOuterContains: "AND tow.unique_id = ?", + wantOuterArgsCount: 2, + wantInnerClauseNotEmpty: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + f := buildDrilldownFilters(tc.reqOptions) + + if tc.wantOuterContains != "" && !strings.Contains(f.outerClause, tc.wantOuterContains) { + t.Errorf("outerClause = %q, want it to contain %q", f.outerClause, tc.wantOuterContains) + } + + if tc.wantOuterNotContains != "" && strings.Contains(f.outerClause, tc.wantOuterNotContains) { + t.Errorf("outerClause = %q, want it to NOT contain %q", f.outerClause, tc.wantOuterNotContains) + } + + if len(f.outerArgs) != tc.wantOuterArgsCount { + t.Errorf("outerArgs count = %d, want %d", len(f.outerArgs), tc.wantOuterArgsCount) + } + + if tc.wantInnerClauseNotEmpty && f.innerClause == "" { + t.Error("innerClause is empty, want non-empty") + } + }) + } +} From bb254b02762e09fed61b5748703d77a119720c40 Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Fri, 21 Aug 2026 05:42:59 +0000 Subject: [PATCH 2/6] TRT-2914: assert capability predicate and args in combined test case Strengthen the "capabilities filter and IgnoreDisruption combined" test case to verify both the capability overlap predicate (AND tow.capabilities && ?) and the disruption exclusion clause are present, and validate the actual argument values rather than just the count. Co-Authored-By: Claude Opus 4.6 --- .../dataprovider/postgres/cr_queries_test.go | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go index fd701c3ab..4bca03b9d 100644 --- a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go +++ b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go @@ -1,9 +1,11 @@ package postgres import ( + "fmt" "strings" "testing" + "github.com/lib/pq" "github.com/openshift/sippy/pkg/apis/api/componentreport/reqopts" ) @@ -11,15 +13,15 @@ func TestBuildDrilldownFilters(t *testing.T) { tests := []struct { name string reqOptions reqopts.RequestOptions - wantOuterContains string + wantOuterContains []string wantOuterNotContains string - wantOuterArgsCount int + wantOuterArgs []any wantInnerClauseNotEmpty bool }{ { - name: "empty options produces no clauses", - reqOptions: reqopts.RequestOptions{}, - wantOuterArgsCount: 0, + name: "empty options produces no clauses", + reqOptions: reqopts.RequestOptions{}, + wantOuterArgs: nil, }, { name: "IgnoreDisruption adds disruption exclusion", @@ -28,8 +30,8 @@ func TestBuildDrilldownFilters(t *testing.T) { IgnoreDisruption: true, }, }, - wantOuterContains: "AND NOT ('Disruption' = ANY(tow.capabilities))", - wantOuterArgsCount: 0, + wantOuterContains: []string{"AND NOT ('Disruption' = ANY(tow.capabilities))"}, + wantOuterArgs: nil, }, { name: "IgnoreDisruption false does not add disruption exclusion", @@ -39,7 +41,7 @@ func TestBuildDrilldownFilters(t *testing.T) { }, }, wantOuterNotContains: "Disruption", - wantOuterArgsCount: 0, + wantOuterArgs: nil, }, { name: "capabilities filter and IgnoreDisruption combined", @@ -51,8 +53,11 @@ func TestBuildDrilldownFilters(t *testing.T) { IgnoreDisruption: true, }, }, - wantOuterContains: "AND NOT ('Disruption' = ANY(tow.capabilities))", - wantOuterArgsCount: 1, + wantOuterContains: []string{ + "AND tow.capabilities && ?", + "AND NOT ('Disruption' = ANY(tow.capabilities))", + }, + wantOuterArgs: []any{pq.Array([]string{"install"})}, }, { name: "single TestIDOption with test ID and capability", @@ -61,8 +66,8 @@ func TestBuildDrilldownFilters(t *testing.T) { {TestID: "test-123", Capability: "install"}, }, }, - wantOuterContains: "AND tow.unique_id = ?", - wantOuterArgsCount: 2, + wantOuterContains: []string{"AND tow.unique_id = ?"}, + wantOuterArgs: []any{"test-123", "install"}, wantInnerClauseNotEmpty: true, }, } @@ -71,16 +76,24 @@ func TestBuildDrilldownFilters(t *testing.T) { t.Run(tc.name, func(t *testing.T) { f := buildDrilldownFilters(tc.reqOptions) - if tc.wantOuterContains != "" && !strings.Contains(f.outerClause, tc.wantOuterContains) { - t.Errorf("outerClause = %q, want it to contain %q", f.outerClause, tc.wantOuterContains) + for _, want := range tc.wantOuterContains { + if !strings.Contains(f.outerClause, want) { + t.Errorf("outerClause = %q, want it to contain %q", f.outerClause, want) + } } if tc.wantOuterNotContains != "" && strings.Contains(f.outerClause, tc.wantOuterNotContains) { t.Errorf("outerClause = %q, want it to NOT contain %q", f.outerClause, tc.wantOuterNotContains) } - if len(f.outerArgs) != tc.wantOuterArgsCount { - t.Errorf("outerArgs count = %d, want %d", len(f.outerArgs), tc.wantOuterArgsCount) + if len(f.outerArgs) != len(tc.wantOuterArgs) { + t.Errorf("outerArgs count = %d, want %d", len(f.outerArgs), len(tc.wantOuterArgs)) + } else { + for i := range tc.wantOuterArgs { + if fmt.Sprintf("%v", f.outerArgs[i]) != fmt.Sprintf("%v", tc.wantOuterArgs[i]) { + t.Errorf("outerArgs[%d] = %v, want %v", i, f.outerArgs[i], tc.wantOuterArgs[i]) + } + } } if tc.wantInnerClauseNotEmpty && f.innerClause == "" { From 06e3b4517d278e3a8493b1643746cf2f28cacc2f Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Fri, 21 Aug 2026 05:51:38 +0000 Subject: [PATCH 3/6] TRT-2914: assert capability predicate in TestIDOption test case Co-Authored-By: Claude Opus 4.6 --- .../dataprovider/postgres/cr_queries_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go index 4bca03b9d..5749962d3 100644 --- a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go +++ b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go @@ -66,7 +66,10 @@ func TestBuildDrilldownFilters(t *testing.T) { {TestID: "test-123", Capability: "install"}, }, }, - wantOuterContains: []string{"AND tow.unique_id = ?"}, + wantOuterContains: []string{ + "AND tow.unique_id = ?", + "AND ? = ANY(tow.capabilities)", + }, wantOuterArgs: []any{"test-123", "install"}, wantInnerClauseNotEmpty: true, }, From 4e317fcdb9abff0b8a41653c129c9db386ba252a Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Fri, 21 Aug 2026 13:32:15 +0000 Subject: [PATCH 4/6] TRT-2914: strengthen drilldown filter test assertions Assert empty outerClause/innerClause for the empty-options case and verify exact innerClause SQL and innerArgs for the TestIDOption case, replacing the weaker non-empty check. Co-Authored-By: Claude Opus 4.6 --- .../dataprovider/postgres/cr_queries_test.go | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go index 5749962d3..5147191cf 100644 --- a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go +++ b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go @@ -11,12 +11,13 @@ import ( func TestBuildDrilldownFilters(t *testing.T) { tests := []struct { - name string - reqOptions reqopts.RequestOptions - wantOuterContains []string - wantOuterNotContains string - wantOuterArgs []any - wantInnerClauseNotEmpty bool + name string + reqOptions reqopts.RequestOptions + wantOuterContains []string + wantOuterNotContains string + wantOuterArgs []any + wantInnerContains []string + wantInnerArgs []any }{ { name: "empty options produces no clauses", @@ -70,8 +71,11 @@ func TestBuildDrilldownFilters(t *testing.T) { "AND tow.unique_id = ?", "AND ? = ANY(tow.capabilities)", }, - wantOuterArgs: []any{"test-123", "install"}, - wantInnerClauseNotEmpty: true, + wantOuterArgs: []any{"test-123", "install"}, + wantInnerContains: []string{ + "AND e.test_id IN (SELECT test_id FROM test_ownerships WHERE unique_id = ?)", + }, + wantInnerArgs: []any{"test-123"}, }, } @@ -79,6 +83,9 @@ func TestBuildDrilldownFilters(t *testing.T) { t.Run(tc.name, func(t *testing.T) { f := buildDrilldownFilters(tc.reqOptions) + if len(tc.wantOuterContains) == 0 && tc.wantOuterArgs == nil && f.outerClause != "" { + t.Errorf("outerClause = %q, want empty", f.outerClause) + } for _, want := range tc.wantOuterContains { if !strings.Contains(f.outerClause, want) { t.Errorf("outerClause = %q, want it to contain %q", f.outerClause, want) @@ -99,8 +106,23 @@ func TestBuildDrilldownFilters(t *testing.T) { } } - if tc.wantInnerClauseNotEmpty && f.innerClause == "" { - t.Error("innerClause is empty, want non-empty") + if len(tc.wantInnerContains) == 0 && tc.wantInnerArgs == nil && f.innerClause != "" { + t.Errorf("innerClause = %q, want empty", f.innerClause) + } + for _, want := range tc.wantInnerContains { + if !strings.Contains(f.innerClause, want) { + t.Errorf("innerClause = %q, want it to contain %q", f.innerClause, want) + } + } + + if len(f.innerArgs) != len(tc.wantInnerArgs) { + t.Errorf("innerArgs count = %d, want %d", len(f.innerArgs), len(tc.wantInnerArgs)) + } else { + for i := range tc.wantInnerArgs { + if fmt.Sprintf("%v", f.innerArgs[i]) != fmt.Sprintf("%v", tc.wantInnerArgs[i]) { + t.Errorf("innerArgs[%d] = %v, want %v", i, f.innerArgs[i], tc.wantInnerArgs[i]) + } + } } }) } From ad96bf9ff33e3152db020efd9c2961d9cdbbb712 Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Fri, 21 Aug 2026 13:42:23 +0000 Subject: [PATCH 5/6] TRT-2914: assert full outerClause in TestIDOption to verify placeholder-argument order Co-Authored-By: Claude Opus 4.6 --- .../dataprovider/postgres/cr_queries_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go index 5147191cf..02a6ecd29 100644 --- a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go +++ b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go @@ -13,6 +13,7 @@ func TestBuildDrilldownFilters(t *testing.T) { tests := []struct { name string reqOptions reqopts.RequestOptions + wantOuterClause string wantOuterContains []string wantOuterNotContains string wantOuterArgs []any @@ -67,6 +68,7 @@ func TestBuildDrilldownFilters(t *testing.T) { {TestID: "test-123", Capability: "install"}, }, }, + wantOuterClause: " AND tow.unique_id = ? AND ? = ANY(tow.capabilities)", wantOuterContains: []string{ "AND tow.unique_id = ?", "AND ? = ANY(tow.capabilities)", @@ -83,6 +85,10 @@ func TestBuildDrilldownFilters(t *testing.T) { t.Run(tc.name, func(t *testing.T) { f := buildDrilldownFilters(tc.reqOptions) + if tc.wantOuterClause != "" && f.outerClause != tc.wantOuterClause { + t.Errorf("outerClause = %q, want %q", f.outerClause, tc.wantOuterClause) + } + if len(tc.wantOuterContains) == 0 && tc.wantOuterArgs == nil && f.outerClause != "" { t.Errorf("outerClause = %q, want empty", f.outerClause) } From 5c8df6287ee9981b0814def75995e109a91b37c9 Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Fri, 21 Aug 2026 17:53:49 +0000 Subject: [PATCH 6/6] TRT-2914: replace unit tests with integration test for IgnoreDisruption filter Replace string-based unit tests in cr_queries_test.go with an integration test that verifies the SQL executes correctly against Postgres, following the project's testing philosophy and the TestCapabilitiesArrayOverlapFilter pattern. Co-Authored-By: Claude Opus 4.6 --- .../dataprovider/postgres/cr_queries_test.go | 135 ------------------ test/integration/component_readiness_test.go | 92 ++++++++++++ 2 files changed, 92 insertions(+), 135 deletions(-) delete mode 100644 pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go diff --git a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go b/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go deleted file mode 100644 index 02a6ecd29..000000000 --- a/pkg/api/componentreadiness/dataprovider/postgres/cr_queries_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package postgres - -import ( - "fmt" - "strings" - "testing" - - "github.com/lib/pq" - "github.com/openshift/sippy/pkg/apis/api/componentreport/reqopts" -) - -func TestBuildDrilldownFilters(t *testing.T) { - tests := []struct { - name string - reqOptions reqopts.RequestOptions - wantOuterClause string - wantOuterContains []string - wantOuterNotContains string - wantOuterArgs []any - wantInnerContains []string - wantInnerArgs []any - }{ - { - name: "empty options produces no clauses", - reqOptions: reqopts.RequestOptions{}, - wantOuterArgs: nil, - }, - { - name: "IgnoreDisruption adds disruption exclusion", - reqOptions: reqopts.RequestOptions{ - AdvancedOption: reqopts.Advanced{ - IgnoreDisruption: true, - }, - }, - wantOuterContains: []string{"AND NOT ('Disruption' = ANY(tow.capabilities))"}, - wantOuterArgs: nil, - }, - { - name: "IgnoreDisruption false does not add disruption exclusion", - reqOptions: reqopts.RequestOptions{ - AdvancedOption: reqopts.Advanced{ - IgnoreDisruption: false, - }, - }, - wantOuterNotContains: "Disruption", - wantOuterArgs: nil, - }, - { - name: "capabilities filter and IgnoreDisruption combined", - reqOptions: reqopts.RequestOptions{ - TestFilters: reqopts.TestFilters{ - Capabilities: []string{"install"}, - }, - AdvancedOption: reqopts.Advanced{ - IgnoreDisruption: true, - }, - }, - wantOuterContains: []string{ - "AND tow.capabilities && ?", - "AND NOT ('Disruption' = ANY(tow.capabilities))", - }, - wantOuterArgs: []any{pq.Array([]string{"install"})}, - }, - { - name: "single TestIDOption with test ID and capability", - reqOptions: reqopts.RequestOptions{ - TestIDOptions: []reqopts.TestIdentification{ - {TestID: "test-123", Capability: "install"}, - }, - }, - wantOuterClause: " AND tow.unique_id = ? AND ? = ANY(tow.capabilities)", - wantOuterContains: []string{ - "AND tow.unique_id = ?", - "AND ? = ANY(tow.capabilities)", - }, - wantOuterArgs: []any{"test-123", "install"}, - wantInnerContains: []string{ - "AND e.test_id IN (SELECT test_id FROM test_ownerships WHERE unique_id = ?)", - }, - wantInnerArgs: []any{"test-123"}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - f := buildDrilldownFilters(tc.reqOptions) - - if tc.wantOuterClause != "" && f.outerClause != tc.wantOuterClause { - t.Errorf("outerClause = %q, want %q", f.outerClause, tc.wantOuterClause) - } - - if len(tc.wantOuterContains) == 0 && tc.wantOuterArgs == nil && f.outerClause != "" { - t.Errorf("outerClause = %q, want empty", f.outerClause) - } - for _, want := range tc.wantOuterContains { - if !strings.Contains(f.outerClause, want) { - t.Errorf("outerClause = %q, want it to contain %q", f.outerClause, want) - } - } - - if tc.wantOuterNotContains != "" && strings.Contains(f.outerClause, tc.wantOuterNotContains) { - t.Errorf("outerClause = %q, want it to NOT contain %q", f.outerClause, tc.wantOuterNotContains) - } - - if len(f.outerArgs) != len(tc.wantOuterArgs) { - t.Errorf("outerArgs count = %d, want %d", len(f.outerArgs), len(tc.wantOuterArgs)) - } else { - for i := range tc.wantOuterArgs { - if fmt.Sprintf("%v", f.outerArgs[i]) != fmt.Sprintf("%v", tc.wantOuterArgs[i]) { - t.Errorf("outerArgs[%d] = %v, want %v", i, f.outerArgs[i], tc.wantOuterArgs[i]) - } - } - } - - if len(tc.wantInnerContains) == 0 && tc.wantInnerArgs == nil && f.innerClause != "" { - t.Errorf("innerClause = %q, want empty", f.innerClause) - } - for _, want := range tc.wantInnerContains { - if !strings.Contains(f.innerClause, want) { - t.Errorf("innerClause = %q, want it to contain %q", f.innerClause, want) - } - } - - if len(f.innerArgs) != len(tc.wantInnerArgs) { - t.Errorf("innerArgs count = %d, want %d", len(f.innerArgs), len(tc.wantInnerArgs)) - } else { - for i := range tc.wantInnerArgs { - if fmt.Sprintf("%v", f.innerArgs[i]) != fmt.Sprintf("%v", tc.wantInnerArgs[i]) { - t.Errorf("innerArgs[%d] = %v, want %v", i, f.innerArgs[i], tc.wantInnerArgs[i]) - } - } - } - }) - } -} diff --git a/test/integration/component_readiness_test.go b/test/integration/component_readiness_test.go index 45722db79..2c3305ab1 100644 --- a/test/integration/component_readiness_test.go +++ b/test/integration/component_readiness_test.go @@ -2967,6 +2967,98 @@ func TestCapabilitiesArrayOverlapFilter(t *testing.T) { }) } +func TestIgnoreDisruptionFilter(t *testing.T) { + dbc := crTestDB(t) + release := "4.16" + + vc := createVariantCombination(t, dbc, []string{"Platform:aws", "Network:ovn"}) + job := createProwJobWithVC(t, dbc, "periodic-e2e-aws-disruption", release, vc) + + testDisruption := intutil.CreateTest(t, dbc, "openshift-tests:[sig-disruption] disruption test") + testStorage := intutil.CreateTest(t, dbc, "openshift-tests:[sig-storage] PVC disruption test") + testRBAC := intutil.CreateTest(t, dbc, "openshift-tests:[sig-auth] RBAC disruption test") + suite := intutil.CreateSuite(t, dbc, "openshift-tests-disruption") + + createTestOwnership(t, dbc, testDisruption.ID, &suite.ID, "openshift-tests:disruption-only", "Disruption", []string{"Disruption"}) + createTestOwnership(t, dbc, testStorage.ID, &suite.ID, "openshift-tests:storage-disruption", "Storage", []string{"PVC", "Disruption"}) + createTestOwnership(t, dbc, testRBAC.ID, &suite.ID, "openshift-tests:rbac-nodisruption", "Authentication", []string{"RBAC"}) + + startMinus1 := civil.Date{Year: 2024, Month: 5, Day: 31} + endMinus1 := civil.Date{Year: 2024, Month: 6, Day: 14} + + for _, testModel := range []models.Test{testDisruption, testStorage, testRBAC} { + createCumulativeSummary(t, dbc, startMinus1, release, testModel.ID, job.ID, suite.ID, 100, 90, 5) + createCumulativeSummary(t, dbc, endMinus1, release, testModel.ID, job.ID, suite.ID, 110, 98, 6) + } + + provider := postgres.NewPostgresProvider(dbc, nil) + + t.Run("IgnoreDisruption excludes tests with Disruption capability", func(t *testing.T) { + opts := defaultReqOptions(release) + opts.AdvancedOption.IgnoreDisruption = true + opts.VariantOption.IncludeVariants = map[string][]string{"Platform": {"aws"}, "Network": {"ovn"}} + _, result, errs := provider.QueryTestStatus(context.Background(), opts) + require.Empty(t, errs) + + nonPlaceholders := filterPlaceholders(result) + for _, ts := range nonPlaceholders { + assert.NotContains(t, ts.Capabilities, "Disruption", + "tests with Disruption capability should be excluded, got %v for %s", ts.Capabilities, ts.TestID) + } + foundRBAC := false + for _, ts := range nonPlaceholders { + switch ts.TestID { + case "openshift-tests:disruption-only": + t.Error("disruption-only test should not appear with IgnoreDisruption=true") + case "openshift-tests:storage-disruption": + t.Error("test with Disruption in capabilities should not appear with IgnoreDisruption=true") + case "openshift-tests:rbac-nodisruption": + foundRBAC = true + } + } + assert.True(t, foundRBAC, "RBAC test without Disruption capability should appear") + }) + + t.Run("IgnoreDisruption false includes all tests", func(t *testing.T) { + opts := defaultReqOptions(release) + opts.AdvancedOption.IgnoreDisruption = false + opts.VariantOption.IncludeVariants = map[string][]string{"Platform": {"aws"}, "Network": {"ovn"}} + _, result, errs := provider.QueryTestStatus(context.Background(), opts) + require.Empty(t, errs) + + nonPlaceholders := filterPlaceholders(result) + foundDisruption := false + foundStorage := false + foundRBAC := false + for _, ts := range nonPlaceholders { + switch ts.TestID { + case "openshift-tests:disruption-only": + foundDisruption = true + case "openshift-tests:storage-disruption": + foundStorage = true + case "openshift-tests:rbac-nodisruption": + foundRBAC = true + } + } + assert.True(t, foundDisruption, "disruption-only test should appear with IgnoreDisruption=false") + assert.True(t, foundStorage, "storage-disruption test should appear with IgnoreDisruption=false") + assert.True(t, foundRBAC, "RBAC test should appear with IgnoreDisruption=false") + }) + + t.Run("IgnoreDisruption combined with capabilities filter", func(t *testing.T) { + opts := defaultReqOptions(release) + opts.AdvancedOption.IgnoreDisruption = true + opts.Capabilities = []string{"PVC"} + opts.VariantOption.IncludeVariants = map[string][]string{"Platform": {"aws"}, "Network": {"ovn"}} + _, result, errs := provider.QueryTestStatus(context.Background(), opts) + require.Empty(t, errs) + + nonPlaceholders := filterPlaceholders(result) + assert.Empty(t, nonPlaceholders, + "storage-disruption has PVC but also Disruption, so it should be excluded; no tests should remain") + }) +} + func TestMixedLifecycleRowsProduceCorrectCounts(t *testing.T) { dbc := crTestDB(t) release := "4.16"