Skip to content

Commit a8f7669

Browse files
canercidamRuteri
andauthored
Tests for validating recipes (#373)
Co-authored-by: Mateusz Morusiewicz <11313015+Ruteri@users.noreply.github.com>
1 parent 874bd08 commit a8f7669

File tree

5 files changed

+94
-24
lines changed

5 files changed

+94
-24
lines changed

main.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,7 @@ var validateCmd = &cobra.Command{
139139
return runValidation(yamlRecipe)
140140
}
141141

142-
// Check base recipes
143-
for _, recipe := range recipes {
144-
if recipe.Name() == recipeName {
145-
return runValidation(recipe)
146-
}
147-
}
148-
149-
return fmt.Errorf("recipe '%s' not found", recipeName)
142+
return fmt.Errorf("recipe file '%s' not found", recipeName)
150143
},
151144
}
152145

@@ -523,11 +516,7 @@ var testCmd = &cobra.Command{
523516
},
524517
}
525518

526-
var recipes = []playground.Recipe{
527-
&playground.L1Recipe{},
528-
&playground.OpRecipe{},
529-
&playground.BuilderNetRecipe{},
530-
}
519+
var recipes = playground.GetBaseRecipes()
531520

532521
func main() {
533522
// Set the embedded custom recipes filesystem for the playground package

playground/cmd_validate.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,27 @@ func ValidateRecipe(recipe Recipe, baseRecipes []Recipe) *ValidationResult {
3333
validateYAMLRecipe(yamlRecipe, baseRecipes, result)
3434
}
3535

36+
// Create a temp output directory for validation
37+
tmpDir, err := os.MkdirTemp("", "playground-validate-")
38+
if err != nil {
39+
result.AddError("failed to create temp directory: %v", err)
40+
return result
41+
}
42+
defer os.RemoveAll(tmpDir)
43+
44+
out, err := NewOutput(tmpDir)
45+
if err != nil {
46+
result.AddError("failed to create output: %v", err)
47+
return result
48+
}
49+
3650
// Build a minimal manifest to validate structure
3751
exCtx := &ExContext{
3852
LogLevel: LevelInfo,
3953
Contender: &ContenderContext{
4054
Enabled: false,
4155
},
56+
Output: out,
4257
}
4358

4459
component := recipe.Apply(exCtx)

playground/custom_recipes_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
package playground
22

33
import (
4+
"io/fs"
45
"os"
56
"path/filepath"
7+
"runtime"
8+
"strings"
69
"testing"
710
"testing/fstest"
811

912
flag "github.com/spf13/pflag"
1013
"github.com/stretchr/testify/require"
1114
)
1215

16+
// getRepoRootFS returns an fs.FS rooted at the repository root for testing real custom-recipes
17+
func getRepoRootFS(t *testing.T) fs.FS {
18+
t.Helper()
19+
_, filename, _, ok := runtime.Caller(0)
20+
require.True(t, ok, "failed to get caller info")
21+
// Go up from playground/ to repo root
22+
repoRoot := filepath.Dir(filepath.Dir(filename))
23+
return os.DirFS(repoRoot)
24+
}
25+
1326
func newTestCustomRecipesFS() fstest.MapFS {
1427
return fstest.MapFS{
1528
// Recipes in group/variant/playground.yaml format
@@ -439,3 +452,47 @@ func (m *mockRecipe) Apply(ctx *ExContext) *Component {
439452
func (m *mockRecipe) Output(manifest *Manifest) map[string]interface{} {
440453
return nil
441454
}
455+
456+
func TestValidateBaseRecipes(t *testing.T) {
457+
baseRecipes := GetBaseRecipes()
458+
require.NotEmpty(t, baseRecipes)
459+
460+
for _, recipe := range baseRecipes {
461+
t.Run(recipe.Name(), func(t *testing.T) {
462+
result := ValidateRecipe(recipe, baseRecipes)
463+
require.Empty(t, result.Errors, "base recipe %s has validation errors: %v", recipe.Name(), result.Errors)
464+
})
465+
}
466+
}
467+
468+
func TestValidateShippedCustomRecipes(t *testing.T) {
469+
// Validate real custom-recipes that ship with the binary
470+
original := CustomRecipesFS
471+
CustomRecipesFS = getRepoRootFS(t)
472+
defer func() { CustomRecipesFS = original }()
473+
474+
baseRecipes := GetBaseRecipes()
475+
476+
customRecipes, err := GetEmbeddedCustomRecipes()
477+
require.NoError(t, err)
478+
require.NotEmpty(t, customRecipes)
479+
480+
for _, name := range customRecipes {
481+
t.Run(name, func(t *testing.T) {
482+
recipe, cleanup, err := LoadCustomRecipe(name, baseRecipes)
483+
require.NoError(t, err)
484+
defer cleanup()
485+
486+
result := ValidateRecipe(recipe, baseRecipes)
487+
488+
// Filter host_path errors (environment-specific)
489+
var errs []string
490+
for _, e := range result.Errors {
491+
if !strings.Contains(e, "host_path does not exist") {
492+
errs = append(errs, e)
493+
}
494+
}
495+
require.Empty(t, errs, "validation errors: %v", errs)
496+
})
497+
}
498+
}

playground/manifest.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ type Recipe interface {
2929
Output(manifest *Manifest) map[string]interface{}
3030
}
3131

32+
// GetBaseRecipes returns all available base recipes
33+
func GetBaseRecipes() []Recipe {
34+
return []Recipe{
35+
&L1Recipe{},
36+
&OpRecipe{},
37+
&BuilderNetRecipe{},
38+
}
39+
}
40+
3241
// Manifest describes a list of services and their dependencies
3342
type Manifest struct {
3443
ID string `json:"session_id"`

playground/recipe_yaml_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ recipe:
433433
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
434434
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
435435

436-
baseRecipes := []Recipe{&L1Recipe{}}
436+
baseRecipes := GetBaseRecipes()
437437

438438
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
439439

@@ -457,7 +457,7 @@ func TestParseYAMLRecipe_MissingBase(t *testing.T) {
457457
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
458458
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
459459

460-
baseRecipes := []Recipe{&L1Recipe{}}
460+
baseRecipes := GetBaseRecipes()
461461

462462
_, err = ParseYAMLRecipe(yamlFile, baseRecipes)
463463

@@ -476,7 +476,7 @@ recipe: {}
476476
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
477477
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
478478

479-
baseRecipes := []Recipe{&L1Recipe{}}
479+
baseRecipes := GetBaseRecipes()
480480

481481
_, err = ParseYAMLRecipe(yamlFile, baseRecipes)
482482

@@ -485,7 +485,7 @@ recipe: {}
485485
}
486486

487487
func TestParseYAMLRecipe_FileNotFound(t *testing.T) {
488-
baseRecipes := []Recipe{&L1Recipe{}}
488+
baseRecipes := GetBaseRecipes()
489489

490490
_, err := ParseYAMLRecipe("/nonexistent/path/recipe.yaml", baseRecipes)
491491

@@ -503,7 +503,7 @@ recipe: {}
503503
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
504504
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
505505

506-
baseRecipes := []Recipe{&L1Recipe{}}
506+
baseRecipes := GetBaseRecipes()
507507

508508
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
509509
require.NoError(t, err)
@@ -527,7 +527,7 @@ recipe:
527527
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
528528
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
529529

530-
baseRecipes := []Recipe{&L1Recipe{}}
530+
baseRecipes := GetBaseRecipes()
531531

532532
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
533533
require.NoError(t, err)
@@ -558,7 +558,7 @@ recipe:
558558
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
559559
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
560560

561-
baseRecipes := []Recipe{&L1Recipe{}}
561+
baseRecipes := GetBaseRecipes()
562562

563563
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
564564
require.NoError(t, err)
@@ -592,7 +592,7 @@ recipe:
592592
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
593593
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
594594

595-
baseRecipes := []Recipe{&L1Recipe{}}
595+
baseRecipes := GetBaseRecipes()
596596

597597
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
598598
require.NoError(t, err)
@@ -627,7 +627,7 @@ recipe:
627627
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
628628
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
629629

630-
baseRecipes := []Recipe{&L1Recipe{}}
630+
baseRecipes := GetBaseRecipes()
631631

632632
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
633633
require.NoError(t, err)
@@ -708,7 +708,7 @@ recipe: {}
708708
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
709709
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
710710

711-
baseRecipes := []Recipe{&L1Recipe{}}
711+
baseRecipes := GetBaseRecipes()
712712

713713
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
714714
require.NoError(t, err)
@@ -738,7 +738,7 @@ recipe:
738738
yamlFile := filepath.Join(tmpDir, "recipe.yaml")
739739
require.NoError(t, os.WriteFile(yamlFile, []byte(yamlContent), 0o644))
740740

741-
baseRecipes := []Recipe{&L1Recipe{}}
741+
baseRecipes := GetBaseRecipes()
742742

743743
recipe, err := ParseYAMLRecipe(yamlFile, baseRecipes)
744744
require.NoError(t, err)

0 commit comments

Comments
 (0)