Skip to content

Commit 26f289a

Browse files
authored
testing: include file-level errors in JUnit skipped elements (#37806)
* testing: include file-level errors in JUnit skipped elements Fixes #37801 * testing: use suite-level system-err for file errors
1 parent b221cc0 commit 26f289a

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: BUG FIXES
2+
body: 'testing: File-level error diagnostics are now included in JUnit XML skipped test elements, ensuring CI/CD pipelines can detect validation failures'
3+
time: 2025-10-24T04:29:00.000000Z
4+
custom:
5+
Issue: "37801"

internal/command/junit/junit.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ func junitXMLTestReport(suite *moduletest.Suite, suiteRunnerStopped bool, source
188188
},
189189
})
190190

191+
// Check if there are file-level errors that will be reported at suite level
192+
hasFileLevelErrors := file.Status == moduletest.Error && file.Diagnostics.HasErrors()
193+
191194
for i, run := range file.Runs {
192195
// Each run is a "test case".
193196

@@ -209,7 +212,7 @@ func junitXMLTestReport(suite *moduletest.Suite, suiteRunnerStopped bool, source
209212
// Depending on run status, add either of: "skipped", "failure", or "error" elements
210213
switch run.Status {
211214
case moduletest.Skip:
212-
testCase.Skipped = skipDetails(i, file, suiteRunnerStopped)
215+
testCase.Skipped = skipDetails(i, file, suiteRunnerStopped, hasFileLevelErrors)
213216

214217
case moduletest.Fail:
215218
// When the test fails we only use error diags that originate from failing assertions
@@ -275,6 +278,16 @@ func junitXMLTestReport(suite *moduletest.Suite, suiteRunnerStopped bool, source
275278
})
276279
}
277280

281+
// Add suite-level system-err if there are file-level errors
282+
if hasFileLevelErrors {
283+
systemErr := &withMessage{
284+
Body: getDiagString(file.Diagnostics, sources),
285+
}
286+
enc.EncodeElement(systemErr, xml.StartElement{
287+
Name: xml.Name{Local: "system-err"},
288+
})
289+
}
290+
278291
enc.EncodeToken(xml.EndElement{Name: suiteName})
279292
}
280293
enc.EncodeToken(xml.EndElement{Name: suitesName})
@@ -300,8 +313,9 @@ func failureMessage(failedAssertions tfdiags.Diagnostics, checkCount int) string
300313
// Test can be skipped due to:
301314
// 1. terraform test recieving an interrupt from users; all unstarted tests will be skipped
302315
// 2. A previous run in a file has failed, causing subsequent run blocks to be skipped
316+
// 3. File-level errors (e.g., invalid variable references) causing all tests to be skipped
303317
// The returned value is used to set content in the "skipped" element
304-
func skipDetails(runIndex int, file *moduletest.File, suiteStopped bool) *withMessage {
318+
func skipDetails(runIndex int, file *moduletest.File, suiteStopped bool, hasFileLevelErrors bool) *withMessage {
305319
if suiteStopped {
306320
// Test suite experienced an interrupt
307321
// This block only handles graceful Stop interrupts, as Cancel interrupts will prevent a JUnit file being produced at all
@@ -323,6 +337,14 @@ func skipDetails(runIndex int, file *moduletest.File, suiteStopped bool) *withMe
323337
}
324338
}
325339
}
340+
341+
// Check for file-level error diagnostics that caused tests to be skipped
342+
// Note: Full diagnostic details are included in suite-level <system-err> element
343+
if hasFileLevelErrors {
344+
return &withMessage{
345+
Message: "Testcase skipped due to file-level errors",
346+
}
347+
}
326348
}
327349

328350
// Unhandled case: This results in <skipped></skipped> with no attributes or body

internal/command/junit/junit_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/hashicorp/terraform/internal/command/junit"
1313
"github.com/hashicorp/terraform/internal/configs/configload"
1414
"github.com/hashicorp/terraform/internal/moduletest"
15+
"github.com/hashicorp/terraform/internal/tfdiags"
1516
)
1617

1718
// This test cannot access sources when contructing output for XML files. Due to this, the majority of testing
@@ -114,6 +115,48 @@ func Test_TestJUnitXMLFile_Save(t *testing.T) {
114115
<skipped></skipped>
115116
</testcase>
116117
</testsuite>
118+
</testsuites>`),
119+
},
120+
"suite-level <system-err> includes file-level error diagnostics when tests are skipped": {
121+
filename: "output.xml",
122+
runner: &local.TestSuiteRunner{},
123+
suite: func() moduletest.Suite {
124+
file := &moduletest.File{
125+
Name: "file1.tftest.hcl",
126+
Status: moduletest.Error,
127+
Runs: []*moduletest.Run{
128+
{
129+
Name: "my_test",
130+
Status: moduletest.Skip,
131+
},
132+
},
133+
}
134+
// Simulate file-level error diagnostic (e.g., invalid variable reference)
135+
var diags tfdiags.Diagnostics
136+
diags = diags.Append(tfdiags.Sourceless(
137+
tfdiags.Error,
138+
"Invalid reference",
139+
"You can only reference global variables within the test file variables block.",
140+
))
141+
file.AppendDiagnostics(diags)
142+
return moduletest.Suite{
143+
Status: moduletest.Error,
144+
Files: map[string]*moduletest.File{
145+
"file1.tftest.hcl": file,
146+
},
147+
}
148+
}(),
149+
expectedOuput: []byte(`<?xml version="1.0" encoding="UTF-8"?><testsuites>
150+
<testsuite name="file1.tftest.hcl" tests="1" skipped="1" failures="0" errors="0">
151+
<testcase name="my_test" classname="file1.tftest.hcl">
152+
<skipped message="Testcase skipped due to file-level errors"></skipped>
153+
</testcase>
154+
<system-err><![CDATA[
155+
Error: Invalid reference
156+
157+
You can only reference global variables within the test file variables block.
158+
]]></system-err>
159+
</testsuite>
117160
</testsuites>`),
118161
},
119162
}

0 commit comments

Comments
 (0)