github.com/freetocompute/snapd@v0.0.0-20210618182524-2fb355d72fd9/testutil/exec_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package testutil 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "os/exec" 27 "path/filepath" 28 29 "gopkg.in/check.v1" 30 ) 31 32 type mockCommandSuite struct{} 33 34 var _ = check.Suite(&mockCommandSuite{}) 35 36 const ( 37 UmountNoFollow = umountNoFollow 38 ) 39 40 func (s *mockCommandSuite) TestMockCommand(c *check.C) { 41 mock := MockCommand(c, "cmd", "true") 42 defer mock.Restore() 43 err := exec.Command("cmd", "first-run", "--arg1", "arg2", "a space").Run() 44 c.Assert(err, check.IsNil) 45 err = exec.Command("cmd", "second-run", "--arg1", "arg2", "a %s").Run() 46 c.Assert(err, check.IsNil) 47 c.Assert(mock.Calls(), check.DeepEquals, [][]string{ 48 {"cmd", "first-run", "--arg1", "arg2", "a space"}, 49 {"cmd", "second-run", "--arg1", "arg2", "a %s"}, 50 }) 51 } 52 53 func (s *mockCommandSuite) TestMockCommandAlso(c *check.C) { 54 mock := MockCommand(c, "fst", "") 55 also := mock.Also("snd", "") 56 defer mock.Restore() 57 58 c.Assert(exec.Command("fst").Run(), check.IsNil) 59 c.Assert(exec.Command("snd").Run(), check.IsNil) 60 c.Check(mock.Calls(), check.DeepEquals, [][]string{{"fst"}, {"snd"}}) 61 c.Check(mock.Calls(), check.DeepEquals, also.Calls()) 62 } 63 64 func (s *mockCommandSuite) TestMockCommandConflictEcho(c *check.C) { 65 mock := MockCommand(c, "do-not-swallow-echo-args", "") 66 defer mock.Restore() 67 68 c.Assert(exec.Command("do-not-swallow-echo-args", "-E", "-n", "-e").Run(), check.IsNil) 69 c.Assert(mock.Calls(), check.DeepEquals, [][]string{ 70 {"do-not-swallow-echo-args", "-E", "-n", "-e"}, 71 }) 72 } 73 74 func (s *mockCommandSuite) TestMockShellchecksWhenAvailable(c *check.C) { 75 tmpDir := c.MkDir() 76 mockShellcheck := MockCommand(c, "shellcheck", fmt.Sprintf(`cat > %s/input`, tmpDir)) 77 defer mockShellcheck.Restore() 78 79 restore := MockShellcheckPath(mockShellcheck.Exe()) 80 defer restore() 81 82 mock := MockCommand(c, "some-command", "echo some-command") 83 84 c.Assert(exec.Command("some-command").Run(), check.IsNil) 85 86 c.Assert(mock.Calls(), check.DeepEquals, [][]string{ 87 {"some-command"}, 88 }) 89 c.Assert(mockShellcheck.Calls(), check.DeepEquals, [][]string{ 90 {"shellcheck", "-s", "bash", "-"}, 91 }) 92 93 scriptData, err := ioutil.ReadFile(mock.Exe()) 94 c.Assert(err, check.IsNil) 95 c.Assert(string(scriptData), Contains, "\necho some-command\n") 96 97 data, err := ioutil.ReadFile(filepath.Join(tmpDir, "input")) 98 c.Assert(err, check.IsNil) 99 c.Assert(data, check.DeepEquals, scriptData) 100 } 101 102 func (s *mockCommandSuite) TestMockNoShellchecksWhenNotAvailable(c *check.C) { 103 mockShellcheck := MockCommand(c, "shellcheck", `echo "i am not called"; exit 1`) 104 defer mockShellcheck.Restore() 105 106 restore := MockShellcheckPath("") 107 defer restore() 108 109 // This would fail with proper shellcheck due to SC2086: Double quote to 110 // prevent globbing and word splitting. 111 mock := MockCommand(c, "some-command", "echo $1") 112 113 c.Assert(exec.Command("some-command").Run(), check.IsNil) 114 115 c.Assert(mock.Calls(), check.DeepEquals, [][]string{ 116 {"some-command"}, 117 }) 118 c.Assert(mockShellcheck.Calls(), check.HasLen, 0) 119 } 120 121 func (s *mockCommandSuite) TestMockCreateAbsPathDir(c *check.C) { 122 // this is an absolute path 123 dir := c.MkDir() 124 125 absPath := filepath.Join(dir, "this/is/nested/command") 126 mock := MockCommand(c, absPath, "") 127 128 c.Assert(exec.Command(absPath).Run(), check.IsNil) 129 c.Assert(mock.Calls(), check.DeepEquals, [][]string{ 130 {"command"}, 131 }) 132 133 binDirRo := filepath.Join(dir, "ro") 134 err := os.MkdirAll(binDirRo, 0000) 135 c.Assert(err, check.IsNil) 136 absPathBad := filepath.Join(binDirRo, "this/fails/command") 137 exp := fmt.Sprintf(`cannot create the directory for mocked command "%[1]s/ro/this/fails/command": mkdir %[1]s/ro/this: permission denied`, dir) 138 c.Assert(func() { MockCommand(c, absPathBad, "") }, check.Panics, exp) 139 }