github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/internal/tests/integration/plugins_test.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package integration 5 6 import ( 7 "testing" 8 9 "gotest.tools/v3/assert" 10 "gotest.tools/v3/fs" 11 ) 12 13 func setupPluginsTest(t *testing.T) *fs.Dir { 14 tmpDir := fs.NewDir(t, "gomplate-inttests", 15 fs.WithFile("foo.sh", "#!/bin/sh\n\necho $*\n", fs.WithMode(0o755)), 16 fs.WithFile("foo.ps1", "echo $args\r\n", fs.WithMode(0o755)), 17 fs.WithFile("bar.sh", "#!/bin/sh\n\neval \"echo $*\"\n", fs.WithMode(0o755)), 18 fs.WithFile("fail.sh", "#!/bin/sh\n\n>&2 echo $1\nexit $2\n", fs.WithMode(0o755)), 19 fs.WithFile("fail.ps1", `param ( 20 [Parameter(Position=0)] 21 [string]$msg, 22 23 [Parameter(Position=1)] 24 [int]$code 25 ) 26 write-error $msg 27 exit $code 28 `, fs.WithMode(0o755)), 29 fs.WithFile("sleep.sh", "#!/bin/sh\n\nexec sleep $1\n", fs.WithMode(0o755)), 30 fs.WithFile("replace.sh", `#!/bin/sh 31 if [ "$#" -eq 2 ]; then 32 exec tr $1 $2 33 elif [ "$#" -eq 3 ]; then 34 printf "=%s" $3 | tr $1 $2 35 fi 36 `, fs.WithMode(0o755)), 37 ) 38 t.Cleanup(tmpDir.Remove) 39 40 return tmpDir 41 } 42 43 func TestPlugins(t *testing.T) { 44 tmpDir := setupPluginsTest(t) 45 o, e, err := cmd(t, "--plugin", "hi="+tmpDir.Join("foo.sh"), 46 "-i", `{{ hi "hello world" }}`).run() 47 assertSuccess(t, o, e, err, "hello world\n") 48 49 o, e, err = cmd(t, "--plugin", "echo="+tmpDir.Join("bar.sh"), 50 "-i", `{{ echo "$HELLO" }}`). 51 withEnv("HELLO", "hello world").run() 52 assertSuccess(t, o, e, err, "hello world\n") 53 } 54 55 func TestPlugins_Errors(t *testing.T) { 56 tmpDir := setupPluginsTest(t) 57 _, _, err := cmd(t, "--plugin", "f=false", 58 "-i", `{{ f }}`).run() 59 assert.ErrorContains(t, err, "exit status 1") 60 61 _, _, err = cmd(t, "--plugin", "f="+tmpDir.Join("fail.sh"), 62 "-i", `{{ f "all is lost" 5 }}`).run() 63 assert.ErrorContains(t, err, "all is lost") 64 assert.ErrorContains(t, err, "error calling f: exit status 5") 65 } 66 67 func TestPlugins_Timeout(t *testing.T) { 68 if testing.Short() { 69 t.Skip() 70 } 71 72 tmpDir := setupPluginsTest(t) 73 74 t.Run("default timeout", func(t *testing.T) { 75 _, _, err := cmd(t, "--plugin", "sleep="+tmpDir.Join("sleep.sh"), 76 "-i", `{{ sleep 10 }}`).run() 77 assert.ErrorContains(t, err, "plugin timed out") 78 }) 79 80 t.Run("envvar timeout", func(t *testing.T) { 81 _, _, err := cmd(t, "--plugin", "sleep="+tmpDir.Join("sleep.sh"), 82 "-i", `{{ sleep 2 }}`). 83 withEnv("GOMPLATE_PLUGIN_TIMEOUT", "500ms").run() 84 assert.ErrorContains(t, err, "plugin timed out") 85 }) 86 } 87 88 func TestPlugins_PipeMode(t *testing.T) { 89 tmpDir := setupPluginsTest(t) 90 91 writeConfig(t, tmpDir, `in: '{{ "hi there" | replace "h" "H" }}' 92 plugins: 93 replace: 94 cmd: `+tmpDir.Join("replace.sh")+` 95 pipe: true 96 `) 97 98 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 99 assert.NilError(t, err) 100 assert.Equal(t, "", e) 101 assert.Equal(t, "Hi tHere", o) 102 103 writeConfig(t, tmpDir, `in: '{{ "hi there" | replace "e" "Z" }}' 104 plugins: 105 replace: 106 cmd: `+tmpDir.Join("replace.sh")+` 107 `) 108 109 o, e, err = cmd(t).withDir(tmpDir.Path()).run() 110 assert.NilError(t, err) 111 assert.Equal(t, "", e) 112 assert.Equal(t, "=hi=thZrZ", o) 113 } 114 115 func TestPlugins_Args(t *testing.T) { 116 tmpDir := setupPluginsTest(t) 117 118 writeConfig(t, tmpDir, `in: '{{ echo "world" }}' 119 plugins: 120 echo: 121 cmd: echo 122 args: [ oh, hello ] 123 `) 124 125 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 126 assertSuccess(t, o, e, err, "oh hello world\n") 127 }