| package packfile |
| |
| import ( |
| "gopkg.in/src-d/go-git.v4/plumbing" |
| "gopkg.in/src-d/go-git.v4/storage/memory" |
| |
| . "gopkg.in/check.v1" |
| ) |
| |
| type DeltaSelectorSuite struct { |
| ds *deltaSelector |
| store *memory.Storage |
| hashes map[string]plumbing.Hash |
| } |
| |
| var _ = Suite(&DeltaSelectorSuite{}) |
| |
| func (s *DeltaSelectorSuite) SetUpTest(c *C) { |
| s.store = memory.NewStorage() |
| s.createTestObjects() |
| s.ds = newDeltaSelector(s.store) |
| } |
| |
| func (s *DeltaSelectorSuite) TestSort(c *C) { |
| var o1 = newObjectToPack(newObject(plumbing.BlobObject, []byte("00000"))) |
| var o4 = newObjectToPack(newObject(plumbing.BlobObject, []byte("0000"))) |
| var o6 = newObjectToPack(newObject(plumbing.BlobObject, []byte("00"))) |
| var o9 = newObjectToPack(newObject(plumbing.BlobObject, []byte("0"))) |
| var o8 = newObjectToPack(newObject(plumbing.TreeObject, []byte("000"))) |
| var o2 = newObjectToPack(newObject(plumbing.TreeObject, []byte("00"))) |
| var o3 = newObjectToPack(newObject(plumbing.TreeObject, []byte("0"))) |
| var o5 = newObjectToPack(newObject(plumbing.CommitObject, []byte("0000"))) |
| var o7 = newObjectToPack(newObject(plumbing.CommitObject, []byte("00"))) |
| |
| toSort := []*ObjectToPack{o1, o2, o3, o4, o5, o6, o7, o8, o9} |
| s.ds.sort(toSort) |
| expected := []*ObjectToPack{o1, o4, o6, o9, o8, o2, o3, o5, o7} |
| c.Assert(toSort, DeepEquals, expected) |
| } |
| |
| type testObject struct { |
| id string |
| object plumbing.EncodedObject |
| } |
| |
| var testObjects []*testObject = []*testObject{{ |
| id: "base", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1000, |
| val: "a", |
| }, { |
| times: 1000, |
| val: "b", |
| }})), |
| }, { |
| id: "smallBase", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1, |
| val: "a", |
| }, { |
| times: 1, |
| val: "b", |
| }, { |
| times: 6, |
| val: "c", |
| }})), |
| }, { |
| id: "smallTarget", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1, |
| val: "a", |
| }, { |
| times: 1, |
| val: "c", |
| }})), |
| }, { |
| id: "target", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1000, |
| val: "a", |
| }, { |
| times: 1000, |
| val: "b", |
| }, { |
| times: 1000, |
| val: "c", |
| }})), |
| }, { |
| id: "o1", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1000, |
| val: "a", |
| }, { |
| times: 1000, |
| val: "b", |
| }})), |
| }, { |
| id: "o2", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1000, |
| val: "a", |
| }, { |
| times: 500, |
| val: "b", |
| }})), |
| }, { |
| id: "o3", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1000, |
| val: "a", |
| }, { |
| times: 499, |
| val: "b", |
| }})), |
| }, { |
| id: "bigBase", |
| object: newObject(plumbing.BlobObject, |
| genBytes([]piece{{ |
| times: 1000000, |
| val: "a", |
| }})), |
| }, { |
| id: "treeType", |
| object: newObject(plumbing.TreeObject, |
| []byte("I am a tree!")), |
| }} |
| |
| func (s *DeltaSelectorSuite) createTestObjects() { |
| s.hashes = make(map[string]plumbing.Hash) |
| for _, o := range testObjects { |
| h, err := s.store.SetEncodedObject(o.object) |
| if err != nil { |
| panic(err) |
| } |
| s.hashes[o.id] = h |
| } |
| } |
| |
| func (s *DeltaSelectorSuite) TestObjectsToPack(c *C) { |
| // Different type |
| hashes := []plumbing.Hash{s.hashes["base"], s.hashes["treeType"]} |
| deltaWindowSize := uint(10) |
| otp, err := s.ds.ObjectsToPack(hashes, deltaWindowSize) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, 2) |
| c.Assert(otp[0].Object, Equals, s.store.Objects[s.hashes["base"]]) |
| c.Assert(otp[1].Object, Equals, s.store.Objects[s.hashes["treeType"]]) |
| |
| // Size radically different |
| hashes = []plumbing.Hash{s.hashes["bigBase"], s.hashes["target"]} |
| otp, err = s.ds.ObjectsToPack(hashes, deltaWindowSize) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, 2) |
| c.Assert(otp[0].Object, Equals, s.store.Objects[s.hashes["bigBase"]]) |
| c.Assert(otp[1].Object, Equals, s.store.Objects[s.hashes["target"]]) |
| |
| // Delta Size Limit with no best delta yet |
| hashes = []plumbing.Hash{s.hashes["smallBase"], s.hashes["smallTarget"]} |
| otp, err = s.ds.ObjectsToPack(hashes, deltaWindowSize) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, 2) |
| c.Assert(otp[0].Object, Equals, s.store.Objects[s.hashes["smallBase"]]) |
| c.Assert(otp[1].Object, Equals, s.store.Objects[s.hashes["smallTarget"]]) |
| |
| // It will create the delta |
| hashes = []plumbing.Hash{s.hashes["base"], s.hashes["target"]} |
| otp, err = s.ds.ObjectsToPack(hashes, deltaWindowSize) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, 2) |
| c.Assert(otp[0].Object, Equals, s.store.Objects[s.hashes["target"]]) |
| c.Assert(otp[0].IsDelta(), Equals, false) |
| c.Assert(otp[1].Original, Equals, s.store.Objects[s.hashes["base"]]) |
| c.Assert(otp[1].IsDelta(), Equals, true) |
| c.Assert(otp[1].Depth, Equals, 1) |
| |
| // If our base is another delta, the depth will increase by one |
| hashes = []plumbing.Hash{ |
| s.hashes["o1"], |
| s.hashes["o2"], |
| s.hashes["o3"], |
| } |
| otp, err = s.ds.ObjectsToPack(hashes, deltaWindowSize) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, 3) |
| c.Assert(otp[0].Object, Equals, s.store.Objects[s.hashes["o1"]]) |
| c.Assert(otp[0].IsDelta(), Equals, false) |
| c.Assert(otp[1].Original, Equals, s.store.Objects[s.hashes["o2"]]) |
| c.Assert(otp[1].IsDelta(), Equals, true) |
| c.Assert(otp[1].Depth, Equals, 1) |
| c.Assert(otp[2].Original, Equals, s.store.Objects[s.hashes["o3"]]) |
| c.Assert(otp[2].IsDelta(), Equals, true) |
| c.Assert(otp[2].Depth, Equals, 2) |
| |
| // Check that objects outside of the sliding window don't produce |
| // a delta. |
| hashes = make([]plumbing.Hash, 0, deltaWindowSize+2) |
| hashes = append(hashes, s.hashes["base"]) |
| for i := uint(0); i < deltaWindowSize; i++ { |
| hashes = append(hashes, s.hashes["smallTarget"]) |
| } |
| hashes = append(hashes, s.hashes["target"]) |
| |
| // Don't sort so we can easily check the sliding window without |
| // creating a bunch of new objects. |
| otp, err = s.ds.objectsToPack(hashes, deltaWindowSize) |
| c.Assert(err, IsNil) |
| err = s.ds.walk(otp, deltaWindowSize) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, int(deltaWindowSize)+2) |
| targetIdx := len(otp) - 1 |
| c.Assert(otp[targetIdx].IsDelta(), Equals, false) |
| |
| // Check that no deltas are created, and the objects are unsorted, |
| // if compression is off. |
| hashes = []plumbing.Hash{s.hashes["base"], s.hashes["target"]} |
| otp, err = s.ds.ObjectsToPack(hashes, 0) |
| c.Assert(err, IsNil) |
| c.Assert(len(otp), Equals, 2) |
| c.Assert(otp[0].Object, Equals, s.store.Objects[s.hashes["base"]]) |
| c.Assert(otp[0].IsDelta(), Equals, false) |
| c.Assert(otp[1].Original, Equals, s.store.Objects[s.hashes["target"]]) |
| c.Assert(otp[1].IsDelta(), Equals, false) |
| c.Assert(otp[1].Depth, Equals, 0) |
| } |
| |
| func (s *DeltaSelectorSuite) TestMaxDepth(c *C) { |
| dsl := s.ds.deltaSizeLimit(0, 0, int(maxDepth), true) |
| c.Assert(dsl, Equals, int64(0)) |
| } |