diff --git a/cmd/hook.go b/cmd/hook.go index 48a64fd197..15ed1eb7f4 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -347,11 +347,10 @@ Forgejo or set your environment appropriately.`, "") } var out io.Writer - var dWriter *delayWriter out = &nilWriter{} if setting.Git.VerbosePush { if setting.Git.VerbosePushDelay > 0 { - dWriter = newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay) + dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay) defer dWriter.Close() out = dWriter } else { @@ -414,7 +413,6 @@ Forgejo or set your environment appropriately.`, "") hookOptions.RefFullNames = refFullNames resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) if extra.HasError() { - _ = dWriter.Close() hookPrintResults(results) return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error) } @@ -434,7 +432,6 @@ Forgejo or set your environment appropriately.`, "") } fmt.Fprintf(out, "Processed %d references in total\n", total) - _ = dWriter.Close() hookPrintResults(results) return nil } @@ -447,7 +444,6 @@ Forgejo or set your environment appropriately.`, "") resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) if resp == nil { - _ = dWriter.Close() hookPrintResults(results) return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error) } @@ -463,9 +459,8 @@ Forgejo or set your environment appropriately.`, "") return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error) } } - _ = dWriter.Close() - hookPrintResults(results) + hookPrintResults(results) return nil } diff --git a/cmd/hook_test.go b/cmd/hook_test.go index d4e16dc411..0c1bee29f4 100644 --- a/cmd/hook_test.go +++ b/cmd/hook_test.go @@ -7,10 +7,20 @@ import ( "bufio" "bytes" "context" + "io" + "net/http" + "net/http/httptest" + "os" "strings" "testing" + "time" + + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" ) func TestPktLine(t *testing.T) { @@ -83,3 +93,72 @@ func TestPktLine(t *testing.T) { assert.Empty(t, w.Bytes()) }) } + +func TestDelayWriter(t *testing.T) { + // Setup the environment. + defer test.MockVariableValue(&setting.InternalToken, "Random")() + defer test.MockVariableValue(&setting.InstallLock, true)() + defer test.MockVariableValue(&setting.Git.VerbosePush, true)() + require.NoError(t, os.Setenv("SSH_ORIGINAL_COMMAND", "true")) + + // Setup the Stdin. + f, err := os.OpenFile(t.TempDir()+"/stdin", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666) + require.NoError(t, err) + _, err = f.Write([]byte("00000000000000000000 00000000000000000001 refs/head/main\n")) + require.NoError(t, err) + _, err = f.Seek(0, 0) + require.NoError(t, err) + defer test.MockVariableValue(os.Stdin, *f)() + + // Setup the server that processes the hooks. + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(time.Millisecond * 600) + })) + defer ts.Close() + defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")() + + app := cli.NewApp() + app.Commands = []*cli.Command{subcmdHookPreReceive} + + // Capture what's being written into stdout + captureStdout := func(t *testing.T) (finish func() (output string)) { + t.Helper() + + r, w, err := os.Pipe() + require.NoError(t, err) + resetStdout := test.MockVariableValue(os.Stdout, *w) + + return func() (output string) { + w.Close() + resetStdout() + + out, err := io.ReadAll(r) + require.NoError(t, err) + return string(out) + } + } + + t.Run("Should delay", func(t *testing.T) { + defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)() + finish := captureStdout(t) + + err = app.Run([]string{"./forgejo", "pre-receive"}) + require.NoError(t, err) + out := finish() + + require.Contains(t, out, "* Checking 1 references") + require.Contains(t, out, "Checked 1 references in total") + }) + + t.Run("Shouldn't delay", func(t *testing.T) { + defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)() + finish := captureStdout(t) + + err = app.Run([]string{"./forgejo", "pre-receive"}) + require.NoError(t, err) + out := finish() + + require.NoError(t, err) + require.Empty(t, out) + }) +}