github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/cmd/hkserver/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/masterhung0112/hk_server/v5/api4" 21 "github.com/masterhung0112/hk_server/v5/model" 22 "github.com/masterhung0112/hk_server/v5/store/storetest/mocks" 23 "github.com/masterhung0112/hk_server/v5/testlib" 24 ) 25 26 var coverprofileCounters map[string]int = make(map[string]int) 27 28 var mainHelper *testlib.MainHelper 29 30 type testHelper struct { 31 *api4.TestHelper 32 33 config *model.Config 34 tempDir string 35 configFilePath string 36 disableAutoConfig bool 37 } 38 39 // Setup creates an instance of testHelper. 40 func Setup(t testing.TB) *testHelper { 41 dir, err := testlib.SetupTestResources() 42 if err != nil { 43 panic("failed to create temporary directory: " + err.Error()) 44 } 45 46 api4TestHelper := api4.Setup(t) 47 48 testHelper := &testHelper{ 49 TestHelper: api4TestHelper, 50 tempDir: dir, 51 configFilePath: filepath.Join(dir, "config-helper.json"), 52 } 53 54 config := &model.Config{} 55 config.SetDefaults() 56 testHelper.SetConfig(config) 57 58 return testHelper 59 } 60 61 // Setup creates an instance of testHelper. 62 func SetupWithStoreMock(t testing.TB) *testHelper { 63 dir, err := testlib.SetupTestResources() 64 if err != nil { 65 panic("failed to create temporary directory: " + err.Error()) 66 } 67 68 api4TestHelper := api4.SetupWithStoreMock(t) 69 systemStore := mocks.SystemStore{} 70 systemStore.On("Get").Return(make(model.StringMap), nil) 71 licenseStore := mocks.LicenseStore{} 72 licenseStore.On("Get", "").Return(&model.LicenseRecord{}, nil) 73 api4TestHelper.App.Srv().Store.(*mocks.Store).On("System").Return(&systemStore) 74 api4TestHelper.App.Srv().Store.(*mocks.Store).On("License").Return(&licenseStore) 75 76 testHelper := &testHelper{ 77 TestHelper: api4TestHelper, 78 tempDir: dir, 79 configFilePath: filepath.Join(dir, "config-helper.json"), 80 } 81 82 config := &model.Config{} 83 config.SetDefaults() 84 testHelper.SetConfig(config) 85 86 return testHelper 87 } 88 89 // InitBasic simply proxies to api4.InitBasic, while still returning a testHelper. 90 func (h *testHelper) InitBasic() *testHelper { 91 h.TestHelper.InitBasic() 92 return h 93 } 94 95 // TemporaryDirectory returns the temporary directory created for user by the test helper. 96 func (h *testHelper) TemporaryDirectory() string { 97 return h.tempDir 98 } 99 100 // Config returns the configuration passed to a running command. 101 func (h *testHelper) Config() *model.Config { 102 return h.config.Clone() 103 } 104 105 // ConfigPath returns the path to the temporary config file passed to a running command. 106 func (h *testHelper) ConfigPath() string { 107 return h.configFilePath 108 } 109 110 // SetConfig replaces the configuration passed to a running command. 111 func (h *testHelper) SetConfig(config *model.Config) { 112 if !testing.Short() { 113 config.SqlSettings = *mainHelper.GetSQLSettings() 114 } 115 116 // Disable strict password requirements for test 117 *config.PasswordSettings.MinimumLength = 5 118 *config.PasswordSettings.Lowercase = false 119 *config.PasswordSettings.Uppercase = false 120 *config.PasswordSettings.Symbol = false 121 *config.PasswordSettings.Number = false 122 123 h.config = config 124 125 if err := ioutil.WriteFile(h.configFilePath, []byte(config.ToJson()), 0600); err != nil { 126 panic("failed to write file " + h.configFilePath + ": " + err.Error()) 127 } 128 } 129 130 // SetAutoConfig configures whether the --config flag is automatically passed to a running command. 131 func (h *testHelper) SetAutoConfig(autoConfig bool) { 132 h.disableAutoConfig = !autoConfig 133 } 134 135 // TearDown cleans up temporary files and assets created during the life of the test helper. 136 func (h *testHelper) TearDown() { 137 h.TestHelper.TearDown() 138 os.RemoveAll(h.tempDir) 139 } 140 141 func (h *testHelper) execArgs(t *testing.T, args []string) []string { 142 ret := []string{"-test.v", "-test.run", "ExecCommand"} 143 if coverprofile := flag.Lookup("test.coverprofile").Value.String(); coverprofile != "" { 144 dir := filepath.Dir(coverprofile) 145 base := filepath.Base(coverprofile) 146 baseParts := strings.SplitN(base, ".", 2) 147 name := strings.Replace(t.Name(), "/", "_", -1) 148 coverprofileCounters[name] = coverprofileCounters[name] + 1 149 baseParts[0] = fmt.Sprintf("%v-%v-%v", baseParts[0], name, coverprofileCounters[name]) 150 ret = append(ret, "-test.coverprofile", filepath.Join(dir, strings.Join(baseParts, "."))) 151 } 152 153 ret = append(ret, "--", "--disableconfigwatch") 154 155 // Unless the test passes a `--config` of its own, create a temporary one from the default 156 // configuration with the current test database applied. 157 hasConfig := h.disableAutoConfig 158 for _, arg := range args { 159 if arg == "--config" { 160 hasConfig = true 161 break 162 } 163 } 164 165 if !hasConfig { 166 ret = append(ret, "--config", h.configFilePath) 167 } 168 169 ret = append(ret, args...) 170 171 return ret 172 } 173 174 func (h *testHelper) cmd(t *testing.T, args []string) *exec.Cmd { 175 path, err := os.Executable() 176 require.NoError(t, err) 177 cmd := exec.Command(path, h.execArgs(t, args)...) 178 179 cmd.Env = []string{} 180 for _, env := range os.Environ() { 181 // Ignore MM_SQLSETTINGS_DATASOURCE from the environment, since we override. 182 if strings.HasPrefix(env, "MM_SQLSETTINGS_DATASOURCE=") { 183 continue 184 } 185 186 cmd.Env = append(cmd.Env, env) 187 } 188 189 return cmd 190 } 191 192 // CheckCommand invokes the test binary, returning the output modified for assertion testing. 193 func (h *testHelper) CheckCommand(t *testing.T, args ...string) string { 194 output, err := h.cmd(t, args).CombinedOutput() 195 require.NoError(t, err, string(output)) 196 return strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(string(output)), "PASS")) 197 } 198 199 // RunCommand invokes the test binary, returning only any error. 200 func (h *testHelper) RunCommand(t *testing.T, args ...string) error { 201 return h.cmd(t, args).Run() 202 } 203 204 // RunCommandWithOutput is a variant of RunCommand that returns the unmodified output and any error. 205 func (h *testHelper) RunCommandWithOutput(t *testing.T, args ...string) (string, error) { 206 cmd := h.cmd(t, args) 207 208 var buf bytes.Buffer 209 reader, writer := io.Pipe() 210 cmd.Stdout = writer 211 cmd.Stderr = writer 212 213 done := make(chan bool) 214 go func() { 215 io.Copy(&buf, reader) 216 close(done) 217 }() 218 219 err := cmd.Run() 220 writer.Close() 221 <-done 222 223 return buf.String(), err 224 }