Skip to content

Make the v2 test outputs API more generally usable to list all executions and include successes#3249

Open
dgoodwin wants to merge 2 commits intoopenshift:mainfrom
dgoodwin:list-test-successes
Open

Make the v2 test outputs API more generally usable to list all executions and include successes#3249
dgoodwin wants to merge 2 commits intoopenshift:mainfrom
dgoodwin:list-test-successes

Conversation

@dgoodwin
Copy link
Contributor

@dgoodwin dgoodwin commented Feb 6, 2026

These changes are intended to let claude examine history further back to determine when a test went bad. In testing it actually seems to work.

End goal will be find the first job run, check what's in the payload, point the finger.

Summary by CodeRabbit

  • New Features

    • Added prow job run ID and job name filtering for test queries
    • Added include_success boolean option to include/exclude successful results
    • Added date range filtering for test results (defaults and 30-day max)
    • Test results now include prow job URLs, prow job names and start times
  • Refactor

    • API test results endpoint path updated to reflect "runs" terminology

@openshift-ci-robot
Copy link

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

Walkthrough

Rename and extend BigQuery test-output retrieval to return test runs with additional filters (prowJobRunIDs, prowJobNames, includeSuccess) and date windowing; add TestOutputBigQuery type and ProwJobURL/StartTime/Success/ProwJobName fields; update HTTP handler and endpoint path to expose the new behavior.

Changes

Cohort / File(s) Summary
Query & API logic
pkg/api/tests.go
Renamed GetTestOutputsFromBigQueryGetTestRunsAndOutputsFromBigQuery. Expanded signature to accept prowJobRunIDs, prowJobNames, includeSuccess, startDate, endDate. SQL now joins jobs to retrieve prowjob_url and prowjob_start, applies dynamic filters (include_success, prow job IDs/names), orders by jobs.prowjob_start DESC, and limits to 500. Result row struct extended with ProwJobURL and ProwJobStart; returns []apitype.TestOutputBigQuery.
API types
pkg/apis/api/types.go
Renamed TestOutput.URLProwJobURL (json tag remains url) and added new exported type TestOutputBigQuery with fields ProwJobURL, Output, TestName, Success, ProwJobName, and StartTime *time.Time.
HTTP handler & routing
pkg/sippyserver/server.go
Renamed handler jsonTestOutputsFromBigQueryjsonTestRunsAndOutputsFromBigQuery. Added parsing for prow_job_run_ids, multi-valued prowjob_name, include_success bool, and start/end date window (defaults and 30-day max). Calls new backend method and changed endpoint from /api/tests/v2/outputs to /api/tests/v2/runs (updated registration, caching, rate limits).
Request param utility
pkg/util/param/param.go
Added ReadBool(req *http.Request, name string, defaultValue bool) (bool, error) and boolRegexp for validating boolean query params. Added include_success to param validation map.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Server as sippyserver
    participant BQ as BigQuery
    Client->>Server: GET /api/tests/v2/runs?test_id=...&prow_job_run_ids=...&include_success=true&start=...&end=...
    Server->>Server: parse params (ids, names, include_success, start/end)
    Server->>BQ: Query with dynamic filters, join jobs, limit 500
    BQ-->>Server: rows (output, test_name, success, prowjob_name, prowjob_url, prowjob_start)
    Server->>Client: JSON response ([]TestOutputBigQuery)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Single Responsibility And Clear Naming ⚠️ Warning The function GetTestRunsAndOutputsFromBigQuery has 8 parameters exceeding guidelines, violating single responsibility principle with multiple distinct concerns. Create FilterOptions struct (ProwJobRunIDs, ProwJobNames, IncludeSuccess) and DateRange struct (StartDate, EndDate) to reduce parameters and improve clarity.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly addresses the main changes: making the v2 test outputs API more usable by enabling filtering/listing of all executions and including successful test results.
Go Error Handling ✅ Passed The pull request follows proper Go error handling patterns. All returned errors are captured and handled appropriately, errors are wrapped with context using fmt.Errorf with %w where needed, no panic() calls are present, and nil pointers are checked before dereferencing.
Sql Injection Prevention ✅ Passed The GetTestRunsAndOutputsFromBigQuery function prevents SQL injection using BigQuery's parameterized queries with named parameters and validates inputs via regex patterns.
Excessive Css In React Should Use Styles ✅ Passed The custom check for 'Excessive CSS in React Should Use Styles' is not applicable to this PR. The PR exclusively modifies Go backend source files with no React components, JSX, or JavaScript/TypeScript files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci bot requested review from smg247 and stbenjam February 6, 2026 16:02
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 6, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dgoodwin

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 6, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/sippyserver/server.go (1)

781-810: ⚠️ Potential issue | 🟡 Minor

Reject start_date after end_date.

Currently a reversed range slips through and yields empty results without feedback. Consider returning 400 when startDate.After(endDate).

💡 Suggested fix
  // Validate date range does not exceed 30 days (expensive query)
+ if startDate.After(endDate) {
+     failureResponse(w, http.StatusBadRequest, "start_date must be on or before end_date")
+     return
+ }
  dateRange := endDate.Sub(startDate)
🤖 Fix all issues with AI agents
In `@pkg/api/tests.go`:
- Around line 69-74: The SQL query string that currently uses INNER JOIN
`openshift-gce-devel.ci_analysis_us.jobs` AS jobs should be changed to a LEFT
JOIN so junit rows without matching job metadata are preserved; keep the INNER
JOIN on test_mapping as-is, change only the join on jobs to LEFT JOIN (alias
jobs) so prowjob_url and prowjob_start may be NULL but all executions are
returned, and ensure the WHERE clause on junit.modified_time remains unchanged.

In `@pkg/apis/api/types.go`:
- Around line 879-886: The DB query in TestOutputs is not selecting the test
status so GORM leaves TestOutput.Success false; update the SELECT in the
TestOutputs query to include prow_job_run_tests.status (or a computed boolean
like (prow_job_run_tests.status = 'success') AS success) so that when GORM scans
into the TestOutput struct the Success field is populated the same way
GetTestRunsAndOutputsFromBigQuery does; locate the TestOutputs function and add
the status/boolean selection and mapping to TestOutput.Success.

Comment on lines +69 to +74
SELECT junit.prowjob_build_id, junit.test_name, junit.success, junit.test_id, junit.branch, junit.prowjob_name, junit.failure_content,
jobs.prowjob_url, jobs.prowjob_start
FROM ` + "`openshift-gce-devel.ci_analysis_us.junit`" + ` AS junit
INNER JOIN test_mapping ON junit.test_name = test_mapping.name AND junit.testsuite = test_mapping.suite
WHERE junit.success = false
AND junit.prowjob_build_id IN UNNEST(@prowJobRunIDs)
AND junit.modified_time BETWEEN DATETIME(@startDate) AND DATETIME(@endDate)
LIMIT 1000`
INNER JOIN ` + "`openshift-gce-devel.ci_analysis_us.jobs`" + ` AS jobs ON junit.prowjob_build_id = jobs.prowjob_build_id
WHERE junit.modified_time BETWEEN DATETIME(@startDate) AND DATETIME(@endDate)`
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid dropping runs when job metadata is missing (use LEFT JOIN).

Line 73 introduces an INNER JOIN on jobs; any junit row without a matching job row will be excluded, which conflicts with the goal to list all executions. A LEFT JOIN preserves those rows while still filling prowjob_url/prowjob_start when available.

💡 Suggested fix
-INNER JOIN `openshift-gce-devel.ci_analysis_us.jobs` AS jobs ON junit.prowjob_build_id = jobs.prowjob_build_id
+LEFT JOIN `openshift-gce-devel.ci_analysis_us.jobs` AS jobs ON junit.prowjob_build_id = jobs.prowjob_build_id
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SELECT junit.prowjob_build_id, junit.test_name, junit.success, junit.test_id, junit.branch, junit.prowjob_name, junit.failure_content,
jobs.prowjob_url, jobs.prowjob_start
FROM ` + "`openshift-gce-devel.ci_analysis_us.junit`" + ` AS junit
INNER JOIN test_mapping ON junit.test_name = test_mapping.name AND junit.testsuite = test_mapping.suite
WHERE junit.success = false
AND junit.prowjob_build_id IN UNNEST(@prowJobRunIDs)
AND junit.modified_time BETWEEN DATETIME(@startDate) AND DATETIME(@endDate)
LIMIT 1000`
INNER JOIN ` + "`openshift-gce-devel.ci_analysis_us.jobs`" + ` AS jobs ON junit.prowjob_build_id = jobs.prowjob_build_id
WHERE junit.modified_time BETWEEN DATETIME(@startDate) AND DATETIME(@endDate)`
SELECT junit.prowjob_build_id, junit.test_name, junit.success, junit.test_id, junit.branch, junit.prowjob_name, junit.failure_content,
jobs.prowjob_url, jobs.prowjob_start
FROM ` + "`openshift-gce-devel.ci_analysis_us.junit`" + ` AS junit
INNER JOIN test_mapping ON junit.test_name = test_mapping.name AND junit.testsuite = test_mapping.suite
LEFT JOIN ` + "`openshift-gce-devel.ci_analysis_us.jobs`" + ` AS jobs ON junit.prowjob_build_id = jobs.prowjob_build_id
WHERE junit.modified_time BETWEEN DATETIME(`@startDate`) AND DATETIME(`@endDate`)`
🤖 Prompt for AI Agents
In `@pkg/api/tests.go` around lines 69 - 74, The SQL query string that currently
uses INNER JOIN `openshift-gce-devel.ci_analysis_us.jobs` AS jobs should be
changed to a LEFT JOIN so junit rows without matching job metadata are
preserved; keep the INNER JOIN on test_mapping as-is, change only the join on
jobs to LEFT JOIN (alias jobs) so prowjob_url and prowjob_start may be NULL but
all executions are returned, and ensure the WHERE clause on junit.modified_time
remains unchanged.

Comment on lines 879 to 886
type TestOutput struct {
URL string `json:"url"`
Output string `json:"output"`
TestName string `json:"test_name,omitempty"`
ProwJobURL string `json:"url"`
GCSBucket string `json:"gcs_bucket,omitempty"`
Output string `json:"output"`
TestName string `json:"test_name,omitempty"`
Success bool `json:"success"`
ProwJobName string `json:"prowjob_name,omitempty"`
StartTime *time.Time `json:"start_time,omitempty"`
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 6, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find all TestOutput struct initializations and their usage patterns
rg -n --type=go 'TestOutput\s*\{' -A 5 -B 2

Repository: openshift/sippy

Length of output: 1274


🏁 Script executed:

# Find any functions that return TestOutput
rg -n --type=go 'func.*TestOutput'

Repository: openshift/sippy

Length of output: 826


🏁 Script executed:

# Search for TestOutput variable assignments
rg -n --type=go ':\s*TestOutput|=.*TestOutput' -B 2 -A 5

Repository: openshift/sippy

Length of output: 3495


🏁 Script executed:

# Read the GetTestOutputsFromDB function in full
sed -n '42,120p' pkg/api/tests.go

Repository: openshift/sippy

Length of output: 2742


🏁 Script executed:

# Read the GetTestRunsAndOutputsFromBigQuery function in full
sed -n '59,200p' pkg/api/tests.go

Repository: openshift/sippy

Length of output: 4626


🏁 Script executed:

# Also check the test_queries.go function that creates TestOutput slices
sed -n '277,350p' pkg/db/query/test_queries.go

Repository: openshift/sippy

Length of output: 2600


🏁 Script executed:

# Check TestOutput struct definition to see if Success is indeed a field
sed -n '870,890p' pkg/apis/api/types.go

Repository: openshift/sippy

Length of output: 792


🏁 Script executed:

# Search for prow_job_run_test_outputs model to see what columns it has
rg -n 'type.*ProwJobRunTestOutput|prow_job_run_test_output' --type=go -A 10

Repository: openshift/sippy

Length of output: 2402


🏁 Script executed:

# Check if there's a success column in the model
rg -n 'Success' pkg/models/ --type=go | head -20

Repository: openshift/sippy

Length of output: 110


🏁 Script executed:

# Check the ProwJobRunTest model to see if it has Success field
rg -n 'type ProwJobRunTest' pkg/db/models/ --type=go -A 20

Repository: openshift/sippy

Length of output: 2439


🏁 Script executed:

# Check the test_queries.go more carefully - does Success come from prow_job_run_tests?
sed -n '277,304p' pkg/db/query/test_queries.go

Repository: openshift/sippy

Length of output: 1166


🏁 Script executed:

# Verify the Status field in ProwJobRunTest is related to success/failure
rg -n 'Status.*TestStatus|TestStatus' pkg/db/models/ --type=go -B 2 -A 2

Repository: openshift/sippy

Length of output: 41


🏁 Script executed:

# Check how Status is used when creating ProwJobRunTest records
rg -n 'ProwJobRunTest.*Status|\.Status\s*=' pkg/dataloader/ --type=go | head -20

Repository: openshift/sippy

Length of output: 549


🏁 Script executed:

# Check the sippyprocessingv1 package to understand TestStatus enum
rg -n 'TestStatus|TestStatusSuccess|TestStatusFailure' --type=go pkg/ | grep -E '(const|TestStatus)' | head -20

Repository: openshift/sippy

Length of output: 2577


🏁 Script executed:

# Let me verify the full context of how the database path constructs TestOutput
# Check if there's any mapping of Status to Success in the database path
rg -n 'Success.*Status|Status.*Success' pkg/api/ --type=go -B 3 -A 3

Repository: openshift/sippy

Length of output: 41


🏁 Script executed:

# Let me check what fields are actually being scanned from the database query
# Look at the Scan call and what struct fields would match
sed -n '275,305p' pkg/db/query/test_queries.go

Repository: openshift/sippy

Length of output: 1170


🏁 Script executed:

# Check if there's a custom scan or mapping happening for TestOutput
rg -n 'type TestOutput' pkg/apis/api/ --type=go -B 2 -A 15

Repository: openshift/sippy

Length of output: 1134


TestOutput.Success in the database query path is always false—add the Status field selection to distinguish real failures.

The database query in pkg/db/query/test_queries.go at lines 277–304 (the TestOutputs function) only selects "prow_job_runs.url, output" and does not retrieve the Status field from the joined prow_job_run_tests table. When GORM scans these results into TestOutput, the Success bool field will be zero-initialized to false for all records, making it indistinguishable from actual test failures.

The BigQuery path (GetTestRunsAndOutputsFromBigQuery) correctly handles this by explicitly selecting junit.success and mapping it to Success. Update the database query to also select prow_job_run_tests.status (or compute Success from it) to match the BigQuery behavior.

🤖 Prompt for AI Agents
In `@pkg/apis/api/types.go` around lines 879 - 886, The DB query in TestOutputs is
not selecting the test status so GORM leaves TestOutput.Success false; update
the SELECT in the TestOutputs query to include prow_job_run_tests.status (or a
computed boolean like (prow_job_run_tests.status = 'success') AS success) so
that when GORM scans into the TestOutput struct the Success field is populated
the same way GetTestRunsAndOutputsFromBigQuery does; locate the TestOutputs
function and add the status/boolean selection and mapping to TestOutput.Success.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this looks legit, this re-used a postgres type. Working on it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@dgoodwin, thank you for confirming and taking care of this! Looking forward to seeing the fix.

@openshift-ci-robot
Copy link

Scheduling required tests:
/test e2e

@openshift-ci-robot
Copy link

Scheduling required tests:
/test e2e

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 6, 2026

@dgoodwin: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants