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 }