Skip to content

Commit 6d6829b

Browse files
committed
git: capture Git STDERR log in Go error
In a609c0b (git: refactor into interface, 2023-02-24), the function 'GitCommandWithStdin()' was replaced with 'gitCommandWithStdin()'. In that update, the STDERR log that was previously written to the error message was removed. Downstream functions (namely 'CreateIncrementalBundle()') relied on the content of that STDERR message to determine behavior. Add it back to the error message to correct the behavor of 'CreateIncrementalBundle()'. Additionally, add unit tests covering 'CreateIncrementalBundle()'. Signed-off-by: Victoria Dye <[email protected]>
1 parent 4b32202 commit 6d6829b

File tree

3 files changed

+137
-2
lines changed

3 files changed

+137
-2
lines changed

internal/git/git.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,19 @@ func (g *gitHelper) gitCommandWithStdin(ctx context.Context, stdinLines []string
5151
for line := range stdinLines {
5252
buffer.Write([]byte(stdinLines[line] + "\n"))
5353
}
54+
55+
stderr := bytes.Buffer{}
5456
exitCode, err := g.cmdExec.Run(ctx, "git", args,
5557
cmd.Stdin(&buffer),
5658
cmd.Stdout(os.Stdout),
57-
cmd.Stderr(os.Stderr),
59+
cmd.Stderr(&stderr),
5860
cmd.Env([]string{"LC_CTYPE=C"}),
5961
)
6062

6163
if err != nil {
6264
return g.logger.Error(ctx, err)
6365
} else if exitCode != 0 {
64-
return g.logger.Errorf(ctx, "'git' exited with status %d", exitCode)
66+
return g.logger.Errorf(ctx, "'git' exited with status %d\n%s", exitCode, stderr.String())
6567
}
6668

6769
return nil

internal/git/git_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package git_test
2+
3+
import (
4+
"context"
5+
"io"
6+
"testing"
7+
8+
"github.com/github/git-bundle-server/internal/cmd"
9+
"github.com/github/git-bundle-server/internal/git"
10+
. "github.com/github/git-bundle-server/internal/testhelpers"
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/mock"
13+
)
14+
15+
var createIncrementalBundleTests = []struct {
16+
title string
17+
18+
// Inputs
19+
repoDir string
20+
filename string
21+
prereqs []string
22+
23+
// Mocked responses
24+
bundleCreate Pair[int, error]
25+
bundleCreateStderr string
26+
27+
// Expected values
28+
expectedBundleCreated bool
29+
expectErr bool
30+
}{
31+
{
32+
"Successful bundle creation",
33+
34+
"/test/home/git-bundle-server/git/test/myrepo/",
35+
"/test/home/git-bundle-server/www/test/myrepo/bundle-1234.bundle",
36+
[]string{"^018d4b8a"},
37+
38+
NewPair[int, error](0, nil),
39+
"",
40+
41+
true,
42+
false,
43+
},
44+
{
45+
"Successful no-op (empty bundle)",
46+
47+
"/test/home/git-bundle-server/git/test/myrepo/",
48+
"/test/home/git-bundle-server/www/test/myrepo/bundle-5678.bundle",
49+
[]string{"^0793b0ce", "^3649daa0"},
50+
51+
NewPair[int, error](128, nil),
52+
"fatal: Refusing to create empty bundle",
53+
54+
false,
55+
false,
56+
},
57+
}
58+
59+
func TestGit_CreateIncrementalBundle(t *testing.T) {
60+
// Set up mocks
61+
testLogger := &MockTraceLogger{}
62+
testCommandExecutor := &MockCommandExecutor{}
63+
64+
gitHelper := git.NewGitHelper(testLogger, testCommandExecutor)
65+
66+
for _, tt := range createIncrementalBundleTests {
67+
t.Run(tt.title, func(t *testing.T) {
68+
var stdin io.Reader
69+
var stdout io.Writer
70+
71+
// Mock responses
72+
testCommandExecutor.On("Run",
73+
mock.Anything,
74+
"git",
75+
[]string{"-C", tt.repoDir, "bundle", "create", tt.filename, "--stdin", "--branches"},
76+
mock.MatchedBy(func(settings []cmd.Setting) bool {
77+
var ok bool
78+
stdin = nil
79+
stdout = nil
80+
for _, setting := range settings {
81+
switch setting.Key {
82+
case cmd.StdinKey:
83+
stdin, ok = setting.Value.(io.Reader)
84+
if !ok {
85+
return false
86+
}
87+
case cmd.StderrKey:
88+
stdout, ok = setting.Value.(io.Writer)
89+
if !ok {
90+
return false
91+
}
92+
}
93+
}
94+
return stdin != nil && stdout != nil
95+
}),
96+
).Run(func(mock.Arguments) {
97+
stdout.Write([]byte(tt.bundleCreateStderr))
98+
}).Return(tt.bundleCreate.First, tt.bundleCreate.Second)
99+
100+
// Run 'CreateIncrementalBundle()'
101+
actualBundleCreated, err := gitHelper.CreateIncrementalBundle(context.Background(), tt.repoDir, tt.filename, tt.prereqs)
102+
103+
// Assert on expected values
104+
assert.Equal(t, tt.expectedBundleCreated, actualBundleCreated)
105+
if tt.expectErr {
106+
assert.Error(t, err)
107+
} else {
108+
assert.NoError(t, err)
109+
}
110+
mock.AssertExpectationsForObjects(t, testCommandExecutor)
111+
112+
// Check the content of stdin
113+
expectedStdin := ConcatLines(tt.prereqs)
114+
expectedStdinLen := len(expectedStdin)
115+
stdinBytes := make([]byte, expectedStdinLen+1)
116+
numRead, err := stdin.Read(stdinBytes)
117+
assert.NoError(t, err)
118+
assert.Equal(t, expectedStdinLen, numRead)
119+
assert.Equal(t, expectedStdin, string(stdinBytes[:expectedStdinLen]))
120+
121+
// Reset mocks
122+
testCommandExecutor.Mock = mock.Mock{}
123+
})
124+
}
125+
}

internal/testhelpers/funcs.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package testhelpers
22

3+
import "github.com/github/git-bundle-server/internal/utils"
4+
35
/********************************************/
46
/************* Helper Functions *************/
57
/********************************************/
68

79
func PtrTo[T any](val T) *T {
810
return &val
911
}
12+
13+
func ConcatLines(lines []string) string {
14+
return utils.Reduce(lines, "", func(line string, out string) string {
15+
return out + line + "\n"
16+
})
17+
}

0 commit comments

Comments
 (0)