code.gitea.io/gitea@v1.21.7/cmd/main_test.go (about)

     1  // Copyright 2022 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package cmd
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"testing"
    13  
    14  	"code.gitea.io/gitea/models/unittest"
    15  	"code.gitea.io/gitea/modules/setting"
    16  	"code.gitea.io/gitea/modules/test"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/urfave/cli/v2"
    20  )
    21  
    22  func TestMain(m *testing.M) {
    23  	unittest.MainTest(m, &unittest.TestOptions{
    24  		GiteaRootPath: "..",
    25  	})
    26  }
    27  
    28  func makePathOutput(workPath, customPath, customConf string) string {
    29  	return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
    30  }
    31  
    32  func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
    33  	app := NewMainApp("version", "version-extra")
    34  	testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
    35  	prepareSubcommandWithConfig(testCmd, appGlobalFlags())
    36  	app.Commands = append(app.Commands, testCmd)
    37  	app.DefaultCommand = testCmd.Name
    38  	return app
    39  }
    40  
    41  type runResult struct {
    42  	Stdout   string
    43  	Stderr   string
    44  	ExitCode int
    45  }
    46  
    47  func runTestApp(app *cli.App, args ...string) (runResult, error) {
    48  	outBuf := new(strings.Builder)
    49  	errBuf := new(strings.Builder)
    50  	app.Writer = outBuf
    51  	app.ErrWriter = errBuf
    52  	exitCode := -1
    53  	defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)()
    54  	defer test.MockVariableValue(&cli.OsExiter, func(code int) {
    55  		if exitCode == -1 {
    56  			exitCode = code // save the exit code once and then reset the writer (to simulate the exit)
    57  			app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard
    58  		}
    59  	})()
    60  	err := RunMainApp(app, args...)
    61  	return runResult{outBuf.String(), errBuf.String(), exitCode}, err
    62  }
    63  
    64  func TestCliCmd(t *testing.T) {
    65  	defaultWorkPath := filepath.Dir(setting.AppPath)
    66  	defaultCustomPath := filepath.Join(defaultWorkPath, "custom")
    67  	defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
    68  
    69  	cli.CommandHelpTemplate = "(command help template)"
    70  	cli.AppHelpTemplate = "(app help template)"
    71  	cli.SubcommandHelpTemplate = "(subcommand help template)"
    72  
    73  	cases := []struct {
    74  		env map[string]string
    75  		cmd string
    76  		exp string
    77  	}{
    78  		// main command help
    79  		{
    80  			cmd: "./gitea help",
    81  			exp: "DEFAULT CONFIGURATION:",
    82  		},
    83  
    84  		// parse paths
    85  		{
    86  			cmd: "./gitea test-cmd",
    87  			exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf),
    88  		},
    89  		{
    90  			cmd: "./gitea -c /tmp/app.ini test-cmd",
    91  			exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
    92  		},
    93  		{
    94  			cmd: "./gitea test-cmd -c /tmp/app.ini",
    95  			exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
    96  		},
    97  		{
    98  			env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
    99  			cmd: "./gitea test-cmd",
   100  			exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"),
   101  		},
   102  		{
   103  			env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
   104  			cmd: "./gitea test-cmd --work-path /tmp/other",
   105  			exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"),
   106  		},
   107  		{
   108  			env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
   109  			cmd: "./gitea test-cmd --config /tmp/app-other.ini",
   110  			exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"),
   111  		},
   112  	}
   113  
   114  	app := newTestApp(func(ctx *cli.Context) error {
   115  		_, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
   116  		return nil
   117  	})
   118  	var envBackup []string
   119  	for _, s := range os.Environ() {
   120  		if strings.HasPrefix(s, "GITEA_") && strings.Contains(s, "=") {
   121  			envBackup = append(envBackup, s)
   122  		}
   123  	}
   124  	clearGiteaEnv := func() {
   125  		for _, s := range os.Environ() {
   126  			if strings.HasPrefix(s, "GITEA_") {
   127  				_ = os.Unsetenv(s)
   128  			}
   129  		}
   130  	}
   131  	defer func() {
   132  		clearGiteaEnv()
   133  		for _, s := range envBackup {
   134  			k, v, _ := strings.Cut(s, "=")
   135  			_ = os.Setenv(k, v)
   136  		}
   137  	}()
   138  
   139  	for _, c := range cases {
   140  		clearGiteaEnv()
   141  		for k, v := range c.env {
   142  			_ = os.Setenv(k, v)
   143  		}
   144  		args := strings.Split(c.cmd, " ") // for test only, "split" is good enough
   145  		r, err := runTestApp(app, args...)
   146  		assert.NoError(t, err, c.cmd)
   147  		assert.NotEmpty(t, c.exp, c.cmd)
   148  		assert.Contains(t, r.Stdout, c.exp, c.cmd)
   149  	}
   150  }
   151  
   152  func TestCliCmdError(t *testing.T) {
   153  	app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") })
   154  	r, err := runTestApp(app, "./gitea", "test-cmd")
   155  	assert.Error(t, err)
   156  	assert.Equal(t, 1, r.ExitCode)
   157  	assert.Equal(t, "", r.Stdout)
   158  	assert.Equal(t, "Command error: normal error\n", r.Stderr)
   159  
   160  	app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) })
   161  	r, err = runTestApp(app, "./gitea", "test-cmd")
   162  	assert.Error(t, err)
   163  	assert.Equal(t, 2, r.ExitCode)
   164  	assert.Equal(t, "", r.Stdout)
   165  	assert.Equal(t, "exit error\n", r.Stderr)
   166  
   167  	app = newTestApp(func(ctx *cli.Context) error { return nil })
   168  	r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
   169  	assert.Error(t, err)
   170  	assert.Equal(t, 1, r.ExitCode)
   171  	assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout)
   172  	assert.Equal(t, "", r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
   173  
   174  	app = newTestApp(func(ctx *cli.Context) error { return nil })
   175  	r, err = runTestApp(app, "./gitea", "test-cmd")
   176  	assert.NoError(t, err)
   177  	assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
   178  	assert.Equal(t, "", r.Stdout)
   179  	assert.Equal(t, "", r.Stderr)
   180  }