Skip to content

Commit d3cdef8

Browse files
authored
Add some tests to clarify the "must-change-password" behavior (go-gitea#30693)
Follow go-gitea#30472: When a user is created by command line `./gitea admin user create`: Old behavior before go-gitea#30472: the first user (admin or non-admin) doesn't need to change password. Revert to the old behavior before go-gitea#30472
1 parent dd301ca commit d3cdef8

9 files changed

+81
-17
lines changed

cmd/admin_user_change_password.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var microcmdUserChangePassword = &cli.Command{
3535
},
3636
&cli.BoolFlag{
3737
Name: "must-change-password",
38-
Usage: "User must change password",
38+
Usage: "User must change password (can be disabled by --must-change-password=false)",
3939
Value: true,
4040
},
4141
},

cmd/admin_user_create.go

+14-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package cmd
55

66
import (
7+
"context"
78
"errors"
89
"fmt"
910

@@ -48,7 +49,7 @@ var microcmdUserCreate = &cli.Command{
4849
},
4950
&cli.BoolFlag{
5051
Name: "must-change-password",
51-
Usage: "Set to false to prevent forcing the user to change their password after initial login",
52+
Usage: "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)",
5253
DisableDefaultText: true,
5354
},
5455
&cli.IntFlag{
@@ -91,11 +92,16 @@ func runCreateUser(c *cli.Context) error {
9192
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
9293
}
9394

94-
ctx, cancel := installSignals()
95-
defer cancel()
96-
97-
if err := initDB(ctx); err != nil {
98-
return err
95+
ctx := c.Context
96+
if !setting.IsInTesting {
97+
// FIXME: need to refactor the "installSignals/initDB" related code later
98+
// it doesn't make sense to call it in (almost) every command action function
99+
var cancel context.CancelFunc
100+
ctx, cancel = installSignals()
101+
defer cancel()
102+
if err := initDB(ctx); err != nil {
103+
return err
104+
}
99105
}
100106

101107
var password string
@@ -123,8 +129,8 @@ func runCreateUser(c *cli.Context) error {
123129
if err != nil {
124130
return fmt.Errorf("IsTableNotEmpty: %w", err)
125131
}
126-
if !hasUserRecord && isAdmin {
127-
// if this is the first admin being created, don't force to change password (keep the old behavior)
132+
if !hasUserRecord {
133+
// if this is the first one being created, don't force to change password (keep the old behavior)
128134
mustChangePassword = false
129135
}
130136
}

cmd/admin_user_create_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package cmd
5+
6+
import (
7+
"fmt"
8+
"strings"
9+
"testing"
10+
11+
"code.gitea.io/gitea/models/db"
12+
"code.gitea.io/gitea/models/unittest"
13+
user_model "code.gitea.io/gitea/models/user"
14+
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestAdminUserCreate(t *testing.T) {
19+
app := NewMainApp(AppVersion{})
20+
21+
reset := func() {
22+
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
23+
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
24+
}
25+
26+
type createCheck struct{ IsAdmin, MustChangePassword bool }
27+
createUser := func(name, args string) createCheck {
28+
assert.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %[email protected] %s --password foobar", name, name, args))))
29+
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name})
30+
return createCheck{u.IsAdmin, u.MustChangePassword}
31+
}
32+
reset()
33+
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u", ""), "first non-admin user doesn't need to change password")
34+
35+
reset()
36+
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u", "--admin"), "first admin user doesn't need to change password")
37+
38+
reset()
39+
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u", "--admin --must-change-password"))
40+
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u2", "--admin"))
41+
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u3", "--admin --must-change-password=false"))
42+
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: true}, createUser("u4", ""))
43+
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u5", "--must-change-password=false"))
44+
}

cmd/main.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,18 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
112112
}
113113
}
114114

115-
func NewMainApp(version, versionExtra string) *cli.App {
115+
type AppVersion struct {
116+
Version string
117+
Extra string
118+
}
119+
120+
func NewMainApp(appVer AppVersion) *cli.App {
116121
app := cli.NewApp()
117122
app.Name = "Gitea"
118123
app.HelpName = "gitea"
119124
app.Usage = "A painless self-hosted Git service"
120125
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
121-
app.Version = version + versionExtra
126+
app.Version = appVer.Version + appVer.Extra
122127
app.EnableBashCompletion = true
123128

124129
// these sub-commands need to use config file

cmd/main_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func makePathOutput(workPath, customPath, customConf string) string {
2828
}
2929

3030
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
31-
app := NewMainApp("version", "version-extra")
31+
app := NewMainApp(AppVersion{})
3232
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
3333
prepareSubcommandWithConfig(testCmd, appGlobalFlags())
3434
app.Commands = append(app.Commands, testCmd)

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func main() {
4242
log.GetManager().Close()
4343
os.Exit(code)
4444
}
45-
app := cmd.NewMainApp(Version, formatBuiltWith())
45+
app := cmd.NewMainApp(cmd.AppVersion{Version: Version, Extra: formatBuiltWith()})
4646
_ = cmd.RunMainApp(app, os.Args...) // all errors should have been handled by the RunMainApp
4747
log.GetManager().Close()
4848
}

models/unittest/testdb.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package unittest
66
import (
77
"context"
88
"fmt"
9-
"log"
109
"os"
1110
"path/filepath"
1211
"strings"
@@ -18,6 +17,7 @@ import (
1817
"code.gitea.io/gitea/modules/base"
1918
"code.gitea.io/gitea/modules/cache"
2019
"code.gitea.io/gitea/modules/git"
20+
"code.gitea.io/gitea/modules/log"
2121
"code.gitea.io/gitea/modules/setting"
2222
"code.gitea.io/gitea/modules/setting/config"
2323
"code.gitea.io/gitea/modules/storage"
@@ -46,6 +46,14 @@ func fatalTestError(fmtStr string, args ...any) {
4646

4747
// InitSettings initializes config provider and load common settings for tests
4848
func InitSettings() {
49+
setting.IsInTesting = true
50+
log.OsExiter = func(code int) {
51+
if code != 0 {
52+
// non-zero exit code (log.Fatal) shouldn't occur during testing, if it happens, show a full stacktrace for more details
53+
panic(fmt.Errorf("non-zero exit code during testing: %d", code))
54+
}
55+
os.Exit(0)
56+
}
4957
if setting.CustomConf == "" {
5058
setting.CustomConf = filepath.Join(setting.CustomPath, "conf/app-unittest-tmp.ini")
5159
_ = os.Remove(setting.CustomConf)
@@ -54,7 +62,7 @@ func InitSettings() {
5462
setting.LoadCommonSettings()
5563

5664
if err := setting.PrepareAppDataPath(); err != nil {
57-
log.Fatalf("Can not prepare APP_DATA_PATH: %v", err)
65+
log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
5866
}
5967
// register the dummy hash algorithm function used in the test fixtures
6068
_ = hash.Register("dummy", hash.NewDummyHasher)

modules/log/logger_global.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ func Critical(format string, v ...any) {
5757
Log(1, ERROR, format, v...)
5858
}
5959

60+
var OsExiter = os.Exit
61+
6062
// Fatal records fatal log and exit process
6163
func Fatal(format string, v ...any) {
6264
Log(1, FATAL, format, v...)
6365
GetManager().Close()
64-
os.Exit(1)
66+
OsExiter(1)
6567
}
6668

6769
func GetLogger(name string) Logger {

tests/test_utils.go

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ func InitTest(requireGitea bool) {
4646
// TODO: Speedup tests that rely on the event source ticker, confirm whether there is any bug or failure.
4747
// setting.UI.Notification.EventSourceUpdateTime = time.Second
4848

49-
setting.IsInTesting = true
5049
setting.AppWorkPath = giteaRoot
5150
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
5251
if requireGitea {

0 commit comments

Comments
 (0)