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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.claude/*local.json
/_output
/openshift.local.*
/third-party
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ require (
github.com/onsi/ginkgo/v2 v2.23.3
github.com/onsi/gomega v1.37.0
github.com/opencontainers/go-digest v1.0.0
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251113163031-356b66aa5c24
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251218142942-7ecc8801b9df
github.com/openshift-kni/commatrix v0.0.5-0.20251111204857-e5a931eff73f
github.com/openshift/api v0.0.0-20251015095338-264e80a2b6e7
github.com/openshift/apiserver-library-go v0.0.0-20251015164739-79d04067059d
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -822,8 +822,8 @@ github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251113163031-356b66aa5c24 h1:bwmjtFaipakIwAyZxnDLgtkLY1Nf1nK9lRCmADvHirE=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251113163031-356b66aa5c24/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251218142942-7ecc8801b9df h1:/KiCxPFpkZN4HErfAX5tyhn6G3ziPFbkGswHVAZKY5Q=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251218142942-7ecc8801b9df/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/openshift-kni/commatrix v0.0.5-0.20251111204857-e5a931eff73f h1:E72Zoc+JImPehBrXkgaCbIDbSFuItvyX6RCaZ0FQE5k=
github.com/openshift-kni/commatrix v0.0.5-0.20251111204857-e5a931eff73f/go.mod h1:cDVdp0eda7EHE6tLuSeo4IqPWdAX/KJK+ogBirIGtsI=
github.com/openshift/api v0.0.0-20251015095338-264e80a2b6e7 h1:Ot2fbEEPmF3WlPQkyEW/bUCV38GMugH/UmZvxpWceNc=
Expand Down
62 changes: 62 additions & 0 deletions pkg/test/extensions/html_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package extensions

import (
"testing"

"github.com/openshift-eng/openshift-tests-extension/pkg/extension/extensiontests"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestViewerHTMLTemplateIsRenderable(t *testing.T) {
// This test ensures the viewer.html template can be parsed by Go's template engine.
// It catches issues like unescaped {{ }} sequences in comments or other content
// that would cause the template to fail to parse.

testData := []byte(`[{"name":"test","result":"passed"}]`)
suiteName := "test-suite"

html, err := extensiontests.RenderResultsHTML(testData, suiteName)
require.NoError(t, err, "viewer.html template should be parseable")
assert.Contains(t, string(html), "test-suite", "rendered HTML should contain suite name")
assert.Contains(t, string(html), `"name":"test"`, "rendered HTML should contain test data")
}

func TestToHTMLModes(t *testing.T) {
// Test that both HTML output modes work correctly
results := ExtensionTestResults{
&ExtensionTestResult{
ExtensionTestResult: &extensiontests.ExtensionTestResult{
Name: "passing-test",
Result: extensiontests.ResultPassed,
Output: "some output",
},
},
&ExtensionTestResult{
ExtensionTestResult: &extensiontests.ExtensionTestResult{
Name: "failing-test",
Result: extensiontests.ResultFailed,
Output: "failure output",
Error: "error message",
},
},
}

t.Run("summary mode", func(t *testing.T) {
html, err := results.ToHTML("test-suite", HTMLOutputSummary)
require.NoError(t, err)
assert.NotEmpty(t, html)
// Summary mode should still contain the test names
assert.Contains(t, string(html), "passing-test")
assert.Contains(t, string(html), "failing-test")
})

t.Run("everything mode", func(t *testing.T) {
html, err := results.ToHTML("test-suite", HTMLOutputEverything)
require.NoError(t, err)
assert.NotEmpty(t, html)
// Everything mode should contain all output
assert.Contains(t, string(html), "some output")
assert.Contains(t, string(html), "failure output")
})
}
44 changes: 44 additions & 0 deletions pkg/test/extensions/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package extensions

import (
"encoding/json"
"fmt"
"strings"

Expand Down Expand Up @@ -95,6 +96,49 @@ type ExtensionTestResult struct {
Source Source `json:"source"`
}

// HTMLOutputMode controls what content is included in the HTML output.
type HTMLOutputMode int

const (
// HTMLOutputSummary elides output/error/details for passed tests to reduce file size.
HTMLOutputSummary HTMLOutputMode = iota
// HTMLOutputEverything includes all output/error/details for all tests.
HTMLOutputEverything
)

// ToHTML converts the extension test results to an HTML representation.
// It marshals origin's results (which include SourceImage/SourceBinary) directly
// and uses RenderResultsHTML to preserve those fields in the HTML output.
func (results ExtensionTestResults) ToHTML(suiteName string, mode HTMLOutputMode) ([]byte, error) {
jsonData, err := json.Marshal(results)
if err != nil {
return nil, fmt.Errorf("failed to marshal results: %w", err)
}

switch mode {
case HTMLOutputSummary:
var copiedResults ExtensionTestResults
if err := json.Unmarshal(jsonData, &copiedResults); err != nil {
return nil, fmt.Errorf("failed to unmarshal results: %w", err)
}
for _, r := range copiedResults {
if r != nil && r.ExtensionTestResult != nil && r.Result == extensiontests.ResultPassed {
r.Error = ""
r.Output = ""
r.Details = nil
}
}
jsonData, err = json.Marshal(copiedResults)
if err != nil {
return nil, fmt.Errorf("failed to marshal results: %w", err)
}
case HTMLOutputEverything:
// Include all output as-is
}

return extensiontests.RenderResultsHTML(jsonData, suiteName)
}

// EnvironmentFlagName enumerates each possible EnvironmentFlag's name to be passed to the external binary
type EnvironmentFlagName string

Expand Down
32 changes: 30 additions & 2 deletions pkg/test/ginkgo/cmd_runsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ func (o *GinkgoRunSuiteOptions) Run(suite *TestSuite, clusterConfig *clusterdisc
fmt.Fprintf(o.Out, "error: Unable to write e2e JUnit xml results: %v", err)
}

if err := writeExtensionTestResults(tests, o.JUnitDir, "extension_test_result_e2e", timeSuffix, o.ErrOut); err != nil {
if err := writeExtensionTestResults(tests, o.JUnitDir, "extension_test_result_e2e", timeSuffix, suite.Name, o.ErrOut); err != nil {
fmt.Fprintf(o.Out, "error: Unable to write e2e Extension Test Result JSON results: %v", err)
}

Expand Down Expand Up @@ -950,7 +950,7 @@ func writeRunSuiteOptions(seed int64, totalNodes, workerNodes, parallelism int,
}
}

func writeExtensionTestResults(tests []*testCase, dir, filePrefix, fileSuffix string, out io.Writer) error {
func writeExtensionTestResults(tests []*testCase, dir, filePrefix, fileSuffix, suiteName string, out io.Writer) error {
// Ensure the directory exists
err := os.MkdirAll(dir, 0755)
if err != nil {
Expand Down Expand Up @@ -989,6 +989,34 @@ func writeExtensionTestResults(tests []*testCase, dir, filePrefix, fileSuffix st
return err
}

// Generate HTML output (summary - elides passed test outputs)
summaryData, err := results.ToHTML(suiteName, extensions.HTMLOutputSummary)
if err != nil {
fmt.Fprintf(out, "Failed to generate summary HTML: %v\n", err)
return err
}

summaryPath := filepath.Join(dir, fmt.Sprintf("%s_%s-summary.html", filePrefix, fileSuffix))
fmt.Fprintf(out, "Writing extension test results HTML to %s\n", summaryPath)
if err := os.WriteFile(summaryPath, summaryData, 0644); err != nil {
fmt.Fprintf(out, "Failed to write HTML file %s: %v\n", summaryPath, err)
return err
}

// Generate HTML output (everything - includes all outputs)
everythingData, err := results.ToHTML(suiteName, extensions.HTMLOutputEverything)
if err != nil {
fmt.Fprintf(out, "Failed to generate everything HTML: %v\n", err)
return err
}

everythingPath := filepath.Join(dir, fmt.Sprintf("%s_%s-everything.html", filePrefix, fileSuffix))
fmt.Fprintf(out, "Writing extension test results HTML to %s\n", everythingPath)
if err := os.WriteFile(everythingPath, everythingData, 0644); err != nil {
fmt.Fprintf(out, "Failed to write HTML file %s: %v\n", everythingPath, err)
return err
}

return nil
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading