@@ -43,12 +43,14 @@ type SuiteResult struct {
4343
4444// Options controls runner behavior.
4545type Options struct {
46- ChartPath string
47- TestFiles []string
48- Parallelism int
49- Cfg * config.Config
50- SnapshotDir string // default: "<chartPath>/tests/snapshots"
51- SnapshotUpdate bool
46+ ChartPath string
47+ TestFiles []string
48+ Parallelism int
49+ Cfg * config.Config
50+ SnapshotDir string // default: "<chartPath>/tests/snapshots"
51+ SnapshotUpdate bool
52+ ValidateSchemas bool // when true, kubeconform-validate each test's rendered docs
53+ KubeVersion string // kubernetes version for schema validation; empty = config.DefaultKubeVersion
5254}
5355
5456// resolveSnapshotDir returns the snapshot directory: the explicit override
@@ -70,14 +72,30 @@ type expandedTest struct {
7072
7173// Run executes all test files and returns suite-level results.
7274func Run (opts Options ) ([]SuiteResult , error ) {
73- slog .Debug ("starting runner" , "files" , len (opts .TestFiles ), "parallelism" , opts .Parallelism )
75+ slog .Debug ("starting runner" , "files" , len (opts .TestFiles ), "parallelism" , opts .Parallelism , "validateSchemas" , opts .ValidateSchemas )
76+
77+ // Build one schema validator shared across all files/tests; its in-memory
78+ // schema cache then amortises across every rendered document.
79+ var schemaValidator * render.SchemaValidator
80+ if opts .ValidateSchemas {
81+ kubeVer := opts .KubeVersion
82+ if kubeVer == "" {
83+ kubeVer = config .DefaultKubeVersion
84+ }
85+ sv , err := render .NewSchemaValidator (kubeVer )
86+ if err != nil {
87+ return nil , fmt .Errorf ("setup error: %w" , err )
88+ }
89+ schemaValidator = sv
90+ slog .Debug ("schema validator ready" , "kubeVersion" , kubeVer )
91+ }
7492
7593 return runParallel (opts .TestFiles , opts .Parallelism , func (_ int , path string ) (SuiteResult , error ) {
76- return runFile (path , opts )
94+ return runFile (path , opts , schemaValidator )
7795 })
7896}
7997
80- func runFile (filePath string , opts Options ) (SuiteResult , error ) {
98+ func runFile (filePath string , opts Options , sv * render. SchemaValidator ) (SuiteResult , error ) {
8199 slog .Debug ("loading test file" , "file" , filePath )
82100 start := time .Now ()
83101
@@ -100,7 +118,7 @@ func runFile(filePath string, opts Options) (SuiteResult, error) {
100118 store := & snapshot.Store {Dir : resolveSnapshotDir (opts .SnapshotDir , opts .ChartPath ), Update : opts .SnapshotUpdate }
101119
102120 for _ , et := range expanded {
103- sr .Results = append (sr .Results , runTest (et , suite , opts , store ))
121+ sr .Results = append (sr .Results , runTest (et , suite , opts , store , sv ))
104122 }
105123 sr .Duration = time .Since (start )
106124 slog .Debug ("suite finished" , "suite" , suite .SuiteName , "tests" , len (sr .Results ), "duration" , sr .Duration )
@@ -226,7 +244,7 @@ func formatEntry(entry map[string]any) string {
226244 return strings .Join (parts , ", " )
227245}
228246
229- func runTest (et expandedTest , suite * dsl.Suite , opts Options , store * snapshot.Store ) (tr TestResult ) {
247+ func runTest (et expandedTest , suite * dsl.Suite , opts Options , store * snapshot.Store , sv * render. SchemaValidator ) (tr TestResult ) {
230248 test := et .Test
231249 tr = TestResult {SuiteName : suite .SuiteName , TestName : et .DisplayName }
232250 start := time .Now ()
@@ -265,6 +283,17 @@ func runTest(et expandedTest, suite *dsl.Suite, opts Options, store *snapshot.St
265283 allDocs = renderResult .Docs
266284 }
267285
286+ // Schema validation (validate tier), on by default unless --no-schema.
287+ if sv != nil && renderErr == nil && len (allDocs ) > 0 {
288+ schemaErrs , err := sv .Validate (allDocs )
289+ if err != nil {
290+ tr .Failures = append (tr .Failures , fmt .Sprintf (" schema validation error: %v" , err ))
291+ }
292+ for _ , se := range schemaErrs {
293+ tr .Failures = append (tr .Failures , fmt .Sprintf (" schema: %s/%s: %s" , se .Kind , se .Name , se .Message ))
294+ }
295+ }
296+
268297 evaluateAssertions (& tr , et , suite , allDocs , renderErr , store )
269298
270299 tr .Pass = len (tr .Failures ) == 0
0 commit comments