package packp
import (
"bytes"
"io"
"sort"
"time"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/pktline"
"github.com/go-git/go-git/v5/plumbing/hash"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
. "gopkg.in/check.v1"
)
type UlReqDecodeSuite struct{}
var _ = Suite(&UlReqDecodeSuite{})
func (s *UlReqDecodeSuite) TestEmpty(c *C) {
ur := NewUploadRequest()
var buf bytes.Buffer
d := newUlReqDecoder(&buf)
err := d.Decode(ur)
c.Assert(err, ErrorMatches, "pkt-line 1: EOF")
}
func (s *UlReqDecodeSuite) TestNoWant(c *C) {
payloads := []string{
"foobar",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*missing 'want '.*")
}
func (s *UlReqDecodeSuite) testDecoderErrorMatches(c *C, input io.Reader, pattern string) {
ur := NewUploadRequest()
d := newUlReqDecoder(input)
err := d.Decode(ur)
c.Assert(err, ErrorMatches, pattern)
}
func (s *UlReqDecodeSuite) TestInvalidFirstHash(c *C) {
payloads := []string{
"want 6ecf0ef2c2dffb796alberto2219af86ec6584e5\n",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*invalid hash.*")
}
func (s *UlReqDecodeSuite) TestWantOK(c *C) {
payloads := []string{
"want 1111111111111111111111111111111111111111",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
c.Assert(ur.Wants, DeepEquals, []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111"),
})
}
func (s *UlReqDecodeSuite) testDecodeOK(c *C, payloads []string) *UploadRequest {
var buf bytes.Buffer
e := pktline.NewEncoder(&buf)
err := e.EncodeString(payloads...)
c.Assert(err, IsNil)
ur := NewUploadRequest()
d := newUlReqDecoder(&buf)
err = d.Decode(ur)
c.Assert(err, IsNil)
return ur
}
func (s *UlReqDecodeSuite) TestWantWithCapabilities(c *C) {
payloads := []string{
"want 1111111111111111111111111111111111111111 ofs-delta multi_ack",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
c.Assert(ur.Wants, DeepEquals, []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111")})
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
}
func (s *UlReqDecodeSuite) TestManyWantsNoCapabilities(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333",
"want 4444444444444444444444444444444444444444",
"want 1111111111111111111111111111111111111111",
"want 2222222222222222222222222222222222222222",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expected := []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111"),
plumbing.NewHash("2222222222222222222222222222222222222222"),
plumbing.NewHash("3333333333333333333333333333333333333333"),
plumbing.NewHash("4444444444444444444444444444444444444444"),
}
sort.Sort(byHash(ur.Wants))
sort.Sort(byHash(expected))
c.Assert(ur.Wants, DeepEquals, expected)
}
type byHash []plumbing.Hash
func (a byHash) Len() int { return len(a) }
func (a byHash) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byHash) Less(i, j int) bool {
ii := [hash.Size]byte(a[i])
jj := [hash.Size]byte(a[j])
return bytes.Compare(ii[:], jj[:]) < 0
}
func (s *UlReqDecodeSuite) TestManyWantsBadWant(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333",
"want 4444444444444444444444444444444444444444",
"foo",
"want 2222222222222222222222222222222222222222",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestManyWantsInvalidHash(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333",
"want 4444444444444444444444444444444444444444",
"want 1234567890abcdef",
"want 2222222222222222222222222222222222222222",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*malformed hash.*")
}
func (s *UlReqDecodeSuite) TestManyWantsWithCapabilities(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"want 4444444444444444444444444444444444444444",
"want 1111111111111111111111111111111111111111",
"want 2222222222222222222222222222222222222222",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expected := []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111"),
plumbing.NewHash("2222222222222222222222222222222222222222"),
plumbing.NewHash("3333333333333333333333333333333333333333"),
plumbing.NewHash("4444444444444444444444444444444444444444"),
}
sort.Sort(byHash(ur.Wants))
sort.Sort(byHash(expected))
c.Assert(ur.Wants, DeepEquals, expected)
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
}
func (s *UlReqDecodeSuite) TestSingleShallowSingleWant(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expectedWants := []plumbing.Hash{
plumbing.NewHash("3333333333333333333333333333333333333333"),
}
expectedShallows := []plumbing.Hash{
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
}
c.Assert(ur.Wants, DeepEquals, expectedWants)
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
c.Assert(ur.Shallows, DeepEquals, expectedShallows)
}
func (s *UlReqDecodeSuite) TestSingleShallowManyWants(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"want 4444444444444444444444444444444444444444",
"want 1111111111111111111111111111111111111111",
"want 2222222222222222222222222222222222222222",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expectedWants := []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111"),
plumbing.NewHash("2222222222222222222222222222222222222222"),
plumbing.NewHash("3333333333333333333333333333333333333333"),
plumbing.NewHash("4444444444444444444444444444444444444444"),
}
sort.Sort(byHash(expectedWants))
expectedShallows := []plumbing.Hash{
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
}
sort.Sort(byHash(ur.Wants))
c.Assert(ur.Wants, DeepEquals, expectedWants)
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
c.Assert(ur.Shallows, DeepEquals, expectedShallows)
}
func (s *UlReqDecodeSuite) TestManyShallowSingleWant(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"shallow cccccccccccccccccccccccccccccccccccccccc",
"shallow dddddddddddddddddddddddddddddddddddddddd",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expectedWants := []plumbing.Hash{
plumbing.NewHash("3333333333333333333333333333333333333333"),
}
expectedShallows := []plumbing.Hash{
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
plumbing.NewHash("cccccccccccccccccccccccccccccccccccccccc"),
plumbing.NewHash("dddddddddddddddddddddddddddddddddddddddd"),
}
sort.Sort(byHash(expectedShallows))
c.Assert(ur.Wants, DeepEquals, expectedWants)
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
sort.Sort(byHash(ur.Shallows))
c.Assert(ur.Shallows, DeepEquals, expectedShallows)
}
func (s *UlReqDecodeSuite) TestManyShallowManyWants(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"want 4444444444444444444444444444444444444444",
"want 1111111111111111111111111111111111111111",
"want 2222222222222222222222222222222222222222",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"shallow cccccccccccccccccccccccccccccccccccccccc",
"shallow dddddddddddddddddddddddddddddddddddddddd",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expectedWants := []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111"),
plumbing.NewHash("2222222222222222222222222222222222222222"),
plumbing.NewHash("3333333333333333333333333333333333333333"),
plumbing.NewHash("4444444444444444444444444444444444444444"),
}
sort.Sort(byHash(expectedWants))
expectedShallows := []plumbing.Hash{
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
plumbing.NewHash("cccccccccccccccccccccccccccccccccccccccc"),
plumbing.NewHash("dddddddddddddddddddddddddddddddddddddddd"),
}
sort.Sort(byHash(expectedShallows))
sort.Sort(byHash(ur.Wants))
c.Assert(ur.Wants, DeepEquals, expectedWants)
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
sort.Sort(byHash(ur.Shallows))
c.Assert(ur.Shallows, DeepEquals, expectedShallows)
}
func (s *UlReqDecodeSuite) TestMalformedShallow(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shalow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestMalformedShallowHash(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*malformed hash.*")
}
func (s *UlReqDecodeSuite) TestMalformedShallowManyShallows(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"shalow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"shallow cccccccccccccccccccccccccccccccccccccccc",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestMalformedDeepenSpec(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen-foo 34",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected deepen.*")
}
func (s *UlReqDecodeSuite) TestMalformedDeepenSingleWant(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"depth 32",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestMalformedDeepenMultiWant(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"want 2222222222222222222222222222222222222222",
"depth 32",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestMalformedDeepenWithSingleShallow(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shallow 2222222222222222222222222222222222222222",
"depth 32",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestMalformedDeepenWithMultiShallow(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"shallow 2222222222222222222222222222222222222222",
"shallow 5555555555555555555555555555555555555555",
"depth 32",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}
func (s *UlReqDecodeSuite) TestDeepenCommits(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen 1234",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
c.Assert(ur.Depth, FitsTypeOf, DepthCommits(0))
commits, ok := ur.Depth.(DepthCommits)
c.Assert(ok, Equals, true)
c.Assert(int(commits), Equals, 1234)
}
func (s *UlReqDecodeSuite) TestDeepenCommitsInfiniteImplicit(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen 0",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
c.Assert(ur.Depth, FitsTypeOf, DepthCommits(0))
commits, ok := ur.Depth.(DepthCommits)
c.Assert(ok, Equals, true)
c.Assert(int(commits), Equals, 0)
}
func (s *UlReqDecodeSuite) TestDeepenCommitsInfiniteExplicit(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
c.Assert(ur.Depth, FitsTypeOf, DepthCommits(0))
commits, ok := ur.Depth.(DepthCommits)
c.Assert(ok, Equals, true)
c.Assert(int(commits), Equals, 0)
}
func (s *UlReqDecodeSuite) TestMalformedDeepenCommits(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen -32",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*negative depth.*")
}
func (s *UlReqDecodeSuite) TestDeepenCommitsEmpty(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen ",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*invalid syntax.*")
}
func (s *UlReqDecodeSuite) TestDeepenSince(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen-since 1420167845", // 2015-01-02T03:04:05+00:00
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expected := time.Date(2015, time.January, 2, 3, 4, 5, 0, time.UTC)
c.Assert(ur.Depth, FitsTypeOf, DepthSince(time.Now()))
since, ok := ur.Depth.(DepthSince)
c.Assert(ok, Equals, true)
c.Assert(time.Time(since).Equal(expected), Equals, true,
Commentf("obtained=%s\nexpected=%s", time.Time(since), expected))
}
func (s *UlReqDecodeSuite) TestDeepenReference(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen-not refs/heads/master",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expected := "refs/heads/master"
c.Assert(ur.Depth, FitsTypeOf, DepthReference(""))
reference, ok := ur.Depth.(DepthReference)
c.Assert(ok, Equals, true)
c.Assert(string(reference), Equals, expected)
}
func (s *UlReqDecodeSuite) TestAll(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"want 4444444444444444444444444444444444444444",
"want 1111111111111111111111111111111111111111",
"want 2222222222222222222222222222222222222222",
"shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"shallow cccccccccccccccccccccccccccccccccccccccc",
"shallow dddddddddddddddddddddddddddddddddddddddd",
"deepen 1234",
pktline.FlushString,
}
ur := s.testDecodeOK(c, payloads)
expectedWants := []plumbing.Hash{
plumbing.NewHash("1111111111111111111111111111111111111111"),
plumbing.NewHash("2222222222222222222222222222222222222222"),
plumbing.NewHash("3333333333333333333333333333333333333333"),
plumbing.NewHash("4444444444444444444444444444444444444444"),
}
sort.Sort(byHash(expectedWants))
sort.Sort(byHash(ur.Wants))
c.Assert(ur.Wants, DeepEquals, expectedWants)
c.Assert(ur.Capabilities.Supports(capability.OFSDelta), Equals, true)
c.Assert(ur.Capabilities.Supports(capability.MultiACK), Equals, true)
expectedShallows := []plumbing.Hash{
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
plumbing.NewHash("cccccccccccccccccccccccccccccccccccccccc"),
plumbing.NewHash("dddddddddddddddddddddddddddddddddddddddd"),
}
sort.Sort(byHash(expectedShallows))
sort.Sort(byHash(ur.Shallows))
c.Assert(ur.Shallows, DeepEquals, expectedShallows)
c.Assert(ur.Depth, FitsTypeOf, DepthCommits(0))
commits, ok := ur.Depth.(DepthCommits)
c.Assert(ok, Equals, true)
c.Assert(int(commits), Equals, 1234)
}
func (s *UlReqDecodeSuite) TestExtraData(c *C) {
payloads := []string{
"want 3333333333333333333333333333333333333333 ofs-delta multi_ack",
"deepen 32",
"foo",
pktline.FlushString,
}
r := toPktLines(c, payloads)
s.testDecoderErrorMatches(c, r, ".*unexpected payload.*")
}