summaryrefslogtreecommitdiff
path: root/actions/recipe_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'actions/recipe_test.go')
-rw-r--r--actions/recipe_test.go370
1 files changed, 370 insertions, 0 deletions
diff --git a/actions/recipe_test.go b/actions/recipe_test.go
new file mode 100644
index 0000000..972bf61
--- /dev/null
+++ b/actions/recipe_test.go
@@ -0,0 +1,370 @@
+package actions_test
+
+import (
+ "github.com/go-debos/debos"
+ "github.com/go-debos/debos/actions"
+ "github.com/stretchr/testify/assert"
+ "io/ioutil"
+ "os"
+ "testing"
+ "strings"
+)
+
+type testRecipe struct {
+ recipe string
+ err string
+}
+
+// Test if incorrect file has been passed
+func TestParse_incorrect_file(t *testing.T) {
+ var err error
+
+ var tests = []struct {
+ filename string
+ err string
+ }{
+ {
+ "non-existing.yaml",
+ "open non-existing.yaml: no such file or directory",
+ },
+ {
+ "/proc",
+ "read /proc: is a directory",
+ },
+ }
+
+ for _, test := range tests {
+ r := actions.Recipe{}
+ err = r.Parse(test.filename, false, false)
+ assert.EqualError(t, err, test.err)
+ }
+}
+
+// Check common recipe syntax
+func TestParse_syntax(t *testing.T) {
+
+ var tests = []testRecipe{
+ // Test if all actions are supported
+ {`
+architecture: arm64
+
+actions:
+ - action: apt
+ - action: debootstrap
+ - action: download
+ - action: filesystem-deploy
+ - action: image-partition
+ - action: ostree-commit
+ - action: ostree-deploy
+ - action: overlay
+ - action: pack
+ - action: raw
+ - action: run
+ - action: unpack
+ - action: recipe
+`,
+ "", // Do not expect failure
+ },
+ // Test of unknown action in list
+ {`
+architecture: arm64
+
+actions:
+ - action: test_unknown_action
+`,
+ "Unknown action: test_unknown_action",
+ },
+ // Test if 'architecture' property absence
+ {`
+actions:
+ - action: raw
+`,
+ "Recipe file must have 'architecture' property",
+ },
+ // Test if no actions listed
+ {`
+architecture: arm64
+`,
+ "Recipe file must have at least one action",
+ },
+ // Test of wrong syntax in Yaml
+ {`wrong`,
+ "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `wrong` into actions.Recipe",
+ },
+ // Test if no actions listed
+ {`
+architecture: arm64
+`,
+ "Recipe file must have at least one action",
+ },
+ }
+
+ for _, test := range tests {
+ runTest(t, test)
+ }
+}
+
+// Check template engine
+func TestParse_template(t *testing.T) {
+
+ var test = testRecipe{
+ // Test template variables
+ `
+{{ $action:= or .action "download" }}
+architecture: arm64
+actions:
+ - action: {{ $action }}
+`,
+ "", // Do not expect failure
+ }
+
+ { // Test of embedded template
+ r := runTest(t, test)
+ assert.Equalf(t, r.Actions[0].String(), "download",
+ "Fail to use embedded variable definition from recipe:%s\n",
+ test.recipe)
+ }
+
+ { // Test of user-defined template variable
+ var templateVars = map[string]string{
+ "action": "pack",
+ }
+
+ r := runTest(t, test, templateVars)
+ assert.Equalf(t, r.Actions[0].String(), "pack",
+ "Fail to redefine variable with user-defined map:%s\n",
+ test.recipe)
+ }
+}
+
+// Test of 'sector' function embedded to recipe package
+func TestParse_sector(t *testing.T) {
+ var testSector = testRecipe{
+ // Fail with unknown action
+ `
+architecture: arm64
+
+actions:
+ - action: {{ sector 42 }}
+`,
+ "Unknown action: 21504",
+ }
+ runTest(t, testSector)
+}
+
+func runTest(t *testing.T, test testRecipe, templateVars ...map[string]string) actions.Recipe {
+ file, err := ioutil.TempFile(os.TempDir(), "recipe")
+ assert.Empty(t, err)
+ defer os.Remove(file.Name())
+
+ file.WriteString(test.recipe)
+ file.Close()
+
+ r := actions.Recipe{}
+ if len(templateVars) == 0 {
+ err = r.Parse(file.Name(), false, false)
+ } else {
+ err = r.Parse(file.Name(), false, false, templateVars[0])
+ }
+
+ failed := false
+
+ if len(test.err) > 0 {
+ // Expected error?
+ failed = !assert.EqualError(t, err, test.err)
+ } else {
+ // Unexpected error
+ failed = !assert.Empty(t, err)
+ }
+
+ if failed {
+ t.Logf("Failed recipe:%s\n", test.recipe)
+ }
+
+ return r
+}
+
+type subRecipe struct {
+ name string
+ recipe string
+}
+
+type testSubRecipe struct {
+ recipe string
+ subrecipe subRecipe
+ err string
+}
+
+func TestSubRecipe(t *testing.T) {
+ // Embedded recipes
+ var recipeAmd64 = subRecipe {
+ "amd64.yaml",
+ `
+architecture: amd64
+
+actions:
+ - action: run
+ command: ok.sh
+`,
+ }
+ var recipeInheritedArch = subRecipe {
+ "inherited.yaml",
+ `
+{{- $architecture := or .architecture "armhf" }}
+architecture: {{ $architecture }}
+
+actions:
+ - action: run
+ command: ok.sh
+`,
+ }
+ var recipeArmhf = subRecipe {
+ "armhf.yaml",
+ `
+architecture: armhf
+
+actions:
+ - action: run
+ command: ok.sh
+`,
+ }
+ var recipeIncluded = subRecipe {
+ "included.yaml",
+ `
+{{- $included_recipe := or .included_recipe "false"}}
+architecture: amd64
+
+actions:
+ - action: run
+ command: ok.sh
+ {{- if ne $included_recipe "true" }}
+ - action: recipe
+ recipe: armhf.yaml
+ {{- end }}
+`,
+ }
+
+ // test recipes
+ var tests = []testSubRecipe {
+ {
+ // Test recipe same architecture OK
+ `
+architecture: amd64
+
+actions:
+ - action: recipe
+ recipe: amd64.yaml
+`,
+ recipeAmd64,
+ "", // Do not expect failure
+ },
+ {
+ // Test recipe with inherited architecture OK
+ `
+architecture: amd64
+
+actions:
+ - action: recipe
+ recipe: inherited.yaml
+`,
+ recipeInheritedArch,
+ "", // Do not expect failure
+ },
+ {
+ // Fail with unknown recipe
+ `
+architecture: amd64
+
+actions:
+ - action: recipe
+ recipe: unknown_recipe.yaml
+`,
+ recipeAmd64,
+ "stat /tmp/unknown_recipe.yaml: no such file or directory",
+ },
+ {
+ // Fail with different architecture recipe
+ `
+architecture: amd64
+
+actions:
+ - action: recipe
+ recipe: armhf.yaml
+`,
+ recipeArmhf,
+ "Expect architecture 'amd64' but got 'armhf'",
+ },
+ {
+ // Test included_recipe prevents parsing OK
+ `
+architecture: amd64
+
+actions:
+ - action: recipe
+ recipe: included.yaml
+`,
+ recipeIncluded,
+ "", // Do not expect failure
+ },
+ }
+
+ for _, test := range tests {
+ runTestWithSubRecipes(t, test)
+ }
+}
+
+func runTestWithSubRecipes(t *testing.T, test testSubRecipe, templateVars ...map[string]string) actions.Recipe {
+ var context debos.DebosContext
+ dir, err := ioutil.TempDir("", "go-debos")
+ assert.Empty(t, err)
+ defer os.RemoveAll(dir)
+
+ file, err := ioutil.TempFile(dir, "recipe")
+ assert.Empty(t, err)
+ defer os.Remove(file.Name())
+
+ file.WriteString(test.recipe)
+ file.Close()
+
+ file_subrecipe, err := os.Create(dir + "/" + test.subrecipe.name)
+ assert.Empty(t, err)
+ defer os.Remove(file_subrecipe.Name())
+
+ file_subrecipe.WriteString(test.subrecipe.recipe)
+ file_subrecipe.Close()
+
+ r := actions.Recipe{}
+ if len(templateVars) == 0 {
+ err = r.Parse(file.Name(), false, false)
+ } else {
+ err = r.Parse(file.Name(), false, false, templateVars[0])
+ }
+
+ // Should not expect error during parse
+ failed := !assert.Empty(t, err)
+
+ if !failed {
+ context.Architecture = r.Architecture
+ context.RecipeDir = dir
+
+ for _, a := range r.Actions {
+ if err = a.Verify(&context); err != nil {
+ break
+ }
+ }
+
+ if len(test.err) > 0 {
+ // Expected error?
+ failed = !assert.EqualError(t, err, strings.Replace(test.err, "/tmp", dir, 1))
+ } else {
+ // Unexpected error
+ failed = !assert.Empty(t, err)
+ }
+ }
+
+ if failed {
+ t.Logf("Failed recipe:%s\n", test.recipe)
+ }
+
+ return r
+}