github.com/rajatvaryani/mattermost-server@v5.11.1+incompatible/cmd/mattermost/commands/cmdtestlib.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package commands 5 6 import ( 7 "bytes" 8 "flag" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "strings" 16 "testing" 17 18 "github.com/stretchr/testify/require" 19 20 "github.com/mattermost/mattermost-server/api4" 21 "github.com/mattermost/mattermost-server/model" 22 "github.com/mattermost/mattermost-server/testlib" 23 ) 24 25 var coverprofileCounters map[string]int = make(map[string]int) 26 27 var mainHelper *testlib.MainHelper 28 29 type testHelper struct { 30 *api4.TestHelper 31 32 config *model.Config 33 tempDir string 34 configFilePath string 35 disableAutoConfig bool 36 } 37 38 // Setup creates an instance of testHelper. 39 func Setup() *testHelper { 40 dir, err := ioutil.TempDir("", "testHelper") 41 if err != nil { 42 panic("failed to create temporary directory: " + err.Error()) 43 } 44 45 api4TestHelper := api4.Setup() 46 47 testHelper := &testHelper{ 48 TestHelper: api4TestHelper, 49 tempDir: dir, 50 configFilePath: filepath.Join(dir, "config-helper.json"), 51 } 52 53 config := &model.Config{} 54 config.SetDefaults() 55 testHelper.SetConfig(config) 56 57 return testHelper 58 } 59 60 // InitBasic simply proxies to api4.InitBasic, while still returning a testHelper. 61 func (h *testHelper) InitBasic() *testHelper { 62 h.TestHelper.InitBasic() 63 return h 64 } 65 66 // TemporaryDirectory returns the temporary directory created for user by the test helper. 67 func (h *testHelper) TemporaryDirectory() string { 68 return h.tempDir 69 } 70 71 // Config returns the configuration passed to a running command. 72 func (h *testHelper) Config() *model.Config { 73 return h.config.Clone() 74 } 75 76 // ConfigPath returns the path to the temporary config file passed to a running command. 77 func (h *testHelper) ConfigPath() string { 78 return h.configFilePath 79 } 80 81 // SetConfig replaces the configuration passed to a running command. 82 func (h *testHelper) SetConfig(config *model.Config) { 83 config.SqlSettings = *mainHelper.GetSqlSettings() 84 h.config = config 85 86 if err := ioutil.WriteFile(h.configFilePath, []byte(config.ToJson()), 0600); err != nil { 87 panic("failed to write file " + h.configFilePath + ": " + err.Error()) 88 } 89 } 90 91 // SetAutoConfig configures whether the --config flag is automatically passed to a running command. 92 func (h *testHelper) SetAutoConfig(autoConfig bool) { 93 h.disableAutoConfig = !autoConfig 94 } 95 96 // TearDown cleans up temporary files and assets created during the life of the test helper. 97 func (h *testHelper) TearDown() { 98 h.TestHelper.TearDown() 99 os.RemoveAll(h.tempDir) 100 } 101 102 func (h *testHelper) execArgs(t *testing.T, args []string) []string { 103 ret := []string{"-test.v", "-test.run", "ExecCommand"} 104 if coverprofile := flag.Lookup("test.coverprofile").Value.String(); coverprofile != "" { 105 dir := filepath.Dir(coverprofile) 106 base := filepath.Base(coverprofile) 107 baseParts := strings.SplitN(base, ".", 2) 108 name := strings.Replace(t.Name(), "/", "_", -1) 109 coverprofileCounters[name] = coverprofileCounters[name] + 1 110 baseParts[0] = fmt.Sprintf("%v-%v-%v", baseParts[0], name, coverprofileCounters[name]) 111 ret = append(ret, "-test.coverprofile", filepath.Join(dir, strings.Join(baseParts, "."))) 112 } 113 114 ret = append(ret, "--", "--disableconfigwatch") 115 116 // Unless the test passes a `--config` of its own, create a temporary one from the default 117 // configuration with the current test database applied. 118 hasConfig := h.disableAutoConfig 119 for _, arg := range args { 120 if arg == "--config" { 121 hasConfig = true 122 break 123 } 124 } 125 126 if !hasConfig { 127 ret = append(ret, "--config", h.configFilePath) 128 } 129 130 ret = append(ret, args...) 131 132 return ret 133 } 134 135 func (h *testHelper) cmd(t *testing.T, args []string) *exec.Cmd { 136 path, err := os.Executable() 137 require.NoError(t, err) 138 cmd := exec.Command(path, h.execArgs(t, args)...) 139 140 cmd.Env = []string{} 141 for _, env := range os.Environ() { 142 // Ignore MM_SQLSETTINGS_DATASOURCE from the environment, since we override. 143 if strings.HasPrefix(env, "MM_SQLSETTINGS_DATASOURCE=") { 144 continue 145 } 146 147 cmd.Env = append(cmd.Env, env) 148 } 149 150 return cmd 151 } 152 153 // CheckCommand invokes the test binary, returning the output modified for assertion testing. 154 func (h *testHelper) CheckCommand(t *testing.T, args ...string) string { 155 output, err := h.cmd(t, args).CombinedOutput() 156 require.NoError(t, err, string(output)) 157 return strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(string(output)), "PASS")) 158 } 159 160 // RunCommand invokes the test binary, returning only any error. 161 func (h *testHelper) RunCommand(t *testing.T, args ...string) error { 162 return h.cmd(t, args).Run() 163 } 164 165 // RunCommandWithOutput is a variant of RunCommand that returns the unmodified output and any error. 166 func (h *testHelper) RunCommandWithOutput(t *testing.T, args ...string) (string, error) { 167 cmd := h.cmd(t, args) 168 169 var buf bytes.Buffer 170 reader, writer := io.Pipe() 171 cmd.Stdout = writer 172 cmd.Stderr = writer 173 174 done := make(chan bool) 175 go func() { 176 io.Copy(&buf, reader) 177 close(done) 178 }() 179 180 err := cmd.Run() 181 writer.Close() 182 <-done 183 184 return buf.String(), err 185 }