1package lfs 2 3import ( 4 "bytes" 5 "crypto/sha256" 6 "encoding/hex" 7 "fmt" 8 "io" 9 "math/rand" 10 "testing" 11 12 "github.com/git-lfs/git-lfs/v3/git" 13 "github.com/git-lfs/gitobj/v2" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16) 17 18func TestPointerScannerWithValidOutput(t *testing.T) { 19 blobs := []*Pointer{ 20 &Pointer{ 21 Version: "https://git-lfs.github.com/spec/v1", 22 Oid: "e71eefd918ea175b8f362611f981f648dbf9888ff74865077cb4c9077728f350", 23 Size: 123, 24 OidType: "sha256", 25 }, 26 &Pointer{ 27 Version: "https://git-lfs.github.com/spec/v1", 28 Oid: "0eb69b651be65d5a61d6bebf2c53c811a5bf8031951111000e2077f4d7fe43b1", 29 Size: 132, 30 OidType: "sha256", 31 }, 32 } 33 34 be, _ := gitobj.NewMemoryBackend(nil) 35 db, _ := gitobj.FromBackend(be) 36 shas := fakeObjectsWithRandoData(t, db, blobs) 37 38 scanner := &PointerScanner{ 39 scanner: git.NewObjectScannerFrom(db), 40 } 41 iter := 0 42 43 for i := 0; i < 5; i++ { 44 assertNextEmptyPointer(t, scanner, shas[iter]) 45 iter++ 46 } 47 48 assertNextPointer(t, scanner, shas[iter], "e71eefd918ea175b8f362611f981f648dbf9888ff74865077cb4c9077728f350") 49 iter++ 50 51 for i := 0; i < 5; i++ { 52 assertNextEmptyPointer(t, scanner, shas[iter]) 53 iter++ 54 } 55 56 assertNextPointer(t, scanner, shas[iter], "0eb69b651be65d5a61d6bebf2c53c811a5bf8031951111000e2077f4d7fe43b1") 57 iter++ 58 59 for i := 0; i < 5; i++ { 60 assertNextEmptyPointer(t, scanner, shas[iter]) 61 iter++ 62 } 63} 64 65func TestPointerScannerWithLargeBlobs(t *testing.T) { 66 buf := bytes.NewBuffer(make([]byte, 0, 1025)) 67 sha := sha256.New() 68 rng := rand.New(rand.NewSource(0)) 69 70 _, err := io.CopyN(io.MultiWriter(sha, buf), rng, 1025) 71 require.Nil(t, err) 72 73 be, _ := gitobj.NewMemoryBackend(nil) 74 db, _ := gitobj.FromBackend(be) 75 76 fake := bytes.NewBuffer(nil) 77 oid := writeFakeBuffer(t, db, fake, buf.Bytes(), buf.Len()) 78 79 scanner := &PointerScanner{ 80 scanner: git.NewObjectScannerFrom(db), 81 } 82 83 require.True(t, scanner.Scan(oid)) 84 assert.Nil(t, scanner.Pointer()) 85 assert.Equal(t, fmt.Sprintf("%x", sha.Sum(nil)), scanner.ContentsSha()) 86} 87 88func assertNextPointer(t *testing.T, scanner *PointerScanner, sha string, oid string) { 89 assert.True(t, scanner.Scan(sha)) 90 assert.Nil(t, scanner.Err()) 91 92 p := scanner.Pointer() 93 94 assert.NotNil(t, p) 95 assert.Equal(t, oid, p.Oid) 96} 97 98func assertNextEmptyPointer(t *testing.T, scanner *PointerScanner, sha string) { 99 assert.True(t, scanner.Scan(sha)) 100 assert.Nil(t, scanner.Err()) 101 102 assert.Nil(t, scanner.Pointer()) 103} 104 105func fakeObjectsWithRandoData(t *testing.T, db *gitobj.ObjectDatabase, blobs []*Pointer) []string { 106 buf := &bytes.Buffer{} 107 rngbuf := make([]byte, 1000) // just under blob size cutoff 108 rng := rand.New(rand.NewSource(0)) 109 oids := make([]string, 0) 110 111 for i := 0; i < 5; i++ { 112 n, err := io.ReadFull(rng, rngbuf) 113 if err != nil { 114 t.Fatalf("error reading from rng: %+v", err) 115 } 116 oids = append(oids, writeFakeBuffer(t, db, buf, rngbuf, n)) 117 } 118 119 for _, b := range blobs { 120 ptrtext := b.Encoded() 121 oids = append(oids, writeFakeBuffer(t, db, buf, []byte(ptrtext), len(ptrtext))) 122 for i := 0; i < 5; i++ { 123 n, err := io.ReadFull(rng, rngbuf) 124 if err != nil { 125 t.Fatalf("error reading from rng: %+v", err) 126 } 127 oids = append(oids, writeFakeBuffer(t, db, buf, rngbuf, n)) 128 } 129 } 130 131 return oids 132} 133 134func writeFakeBuffer(t *testing.T, db *gitobj.ObjectDatabase, buf *bytes.Buffer, by []byte, size int) string { 135 oid, _ := db.WriteBlob(gitobj.NewBlobFromBytes(by)) 136 return hex.EncodeToString(oid) 137} 138