1package catfile
2
3import (
4	"bytes"
5	"testing"
6
7	"github.com/golang/protobuf/ptypes/timestamp"
8	"github.com/stretchr/testify/require"
9	"gitlab.com/gitlab-org/gitaly/v14/internal/git"
10	"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
11	"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
12	"google.golang.org/grpc/metadata"
13)
14
15func TestParseRawCommit(t *testing.T) {
16	info := &ObjectInfo{
17		Oid:  "a984dfa4dee018c6d5f5f57ffec0d0e22763df16",
18		Type: "commit",
19	}
20
21	// Valid-but-interesting commits should be test at the FindCommit level.
22	// Invalid objects (that Git would complain about during fsck) can be
23	// tested here.
24	//
25	// Once a repository contains a pathological object it can be hard to get
26	// rid of it. Because of this I think it's nicer to ignore such objects
27	// than to throw hard errors.
28	testCases := []struct {
29		desc string
30		in   []byte
31		out  *gitalypb.GitCommit
32	}{
33		{
34			desc: "empty commit object",
35			in:   []byte{},
36			out:  &gitalypb.GitCommit{Id: info.Oid.String()},
37		},
38		{
39			desc: "no email",
40			in:   []byte("author Jane Doe"),
41			out: &gitalypb.GitCommit{
42				Id:     info.Oid.String(),
43				Author: &gitalypb.CommitAuthor{Name: []byte("Jane Doe")},
44			},
45		},
46		{
47			desc: "unmatched <",
48			in:   []byte("author Jane Doe <janedoe@example.com"),
49			out: &gitalypb.GitCommit{
50				Id:     info.Oid.String(),
51				Author: &gitalypb.CommitAuthor{Name: []byte("Jane Doe")},
52			},
53		},
54		{
55			desc: "unmatched >",
56			in:   []byte("author Jane Doe janedoe@example.com>"),
57			out: &gitalypb.GitCommit{
58				Id:     info.Oid.String(),
59				Author: &gitalypb.CommitAuthor{Name: []byte("Jane Doe janedoe@example.com>")},
60			},
61		},
62		{
63			desc: "missing date",
64			in:   []byte("author Jane Doe <janedoe@example.com> "),
65			out: &gitalypb.GitCommit{
66				Id:     info.Oid.String(),
67				Author: &gitalypb.CommitAuthor{Name: []byte("Jane Doe"), Email: []byte("janedoe@example.com")},
68			},
69		},
70		{
71			desc: "date too high",
72			in:   []byte("author Jane Doe <janedoe@example.com> 9007199254740993 +0200"),
73			out: &gitalypb.GitCommit{
74				Id: info.Oid.String(),
75				Author: &gitalypb.CommitAuthor{
76					Name:     []byte("Jane Doe"),
77					Email:    []byte("janedoe@example.com"),
78					Date:     &timestamp.Timestamp{Seconds: 9223371974719179007},
79					Timezone: []byte("+0200"),
80				},
81			},
82		},
83		{
84			desc: "date negative",
85			in:   []byte("author Jane Doe <janedoe@example.com> -1 +0200"),
86			out: &gitalypb.GitCommit{
87				Id: info.Oid.String(),
88				Author: &gitalypb.CommitAuthor{
89					Name:     []byte("Jane Doe"),
90					Email:    []byte("janedoe@example.com"),
91					Date:     &timestamp.Timestamp{Seconds: 9223371974719179007},
92					Timezone: []byte("+0200"),
93				},
94			},
95		},
96	}
97
98	for _, tc := range testCases {
99		t.Run(tc.desc, func(t *testing.T) {
100			info.Size = int64(len(tc.in))
101			out, err := parseRawCommit(bytes.NewBuffer(tc.in), info)
102			require.NoError(t, err, "parse error")
103			require.Equal(t, tc.out, out)
104		})
105	}
106}
107
108func TestGetCommit(t *testing.T) {
109	ctx, cancel := testhelper.Context()
110	defer cancel()
111
112	_, c, _ := setupBatch(t, ctx)
113
114	ctx = metadata.NewIncomingContext(ctx, metadata.MD{})
115
116	const commitSha = "2d1db523e11e777e49377cfb22d368deec3f0793"
117	const commitMsg = "Correct test_env.rb path for adding branch\n"
118	const blobSha = "c60514b6d3d6bf4bec1030f70026e34dfbd69ad5"
119
120	testCases := []struct {
121		desc     string
122		revision string
123		errStr   string
124	}{
125		{
126			desc:     "commit",
127			revision: commitSha,
128		},
129		{
130			desc:     "not existing commit",
131			revision: "not existing revision",
132			errStr:   "object not found",
133		},
134		{
135			desc:     "blob sha",
136			revision: blobSha,
137			errStr:   "object not found",
138		},
139	}
140
141	for _, tc := range testCases {
142		t.Run(tc.desc, func(t *testing.T) {
143			c, err := GetCommit(ctx, c, git.Revision(tc.revision))
144
145			if tc.errStr == "" {
146				require.NoError(t, err)
147				require.Equal(t, commitMsg, string(c.Body))
148			} else {
149				require.EqualError(t, err, tc.errStr)
150			}
151		})
152	}
153}
154
155func TestGetCommitWithTrailers(t *testing.T) {
156	ctx, cancel := testhelper.Context()
157	defer cancel()
158
159	cfg, c, testRepo := setupBatch(t, ctx)
160
161	ctx = metadata.NewIncomingContext(ctx, metadata.MD{})
162
163	commit, err := GetCommitWithTrailers(ctx, git.NewExecCommandFactory(cfg), testRepo, c, "5937ac0a7beb003549fc5fd26fc247adbce4a52e")
164
165	require.NoError(t, err)
166
167	require.Equal(t, commit.Trailers, []*gitalypb.CommitTrailer{
168		{
169			Key:   []byte("Signed-off-by"),
170			Value: []byte("Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>"),
171		},
172	})
173}
174