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