github.com/nhannv/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  }