github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/internal/repository/index_test.go (about)

     1  package repository_test
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/restic/restic/internal/repository"
     8  	"github.com/restic/restic/internal/restic"
     9  	rtest "github.com/restic/restic/internal/test"
    10  )
    11  
    12  func TestIndexSerialize(t *testing.T) {
    13  	type testEntry struct {
    14  		id             restic.ID
    15  		pack           restic.ID
    16  		tpe            restic.BlobType
    17  		offset, length uint
    18  	}
    19  	tests := []testEntry{}
    20  
    21  	idx := repository.NewIndex()
    22  
    23  	// create 50 packs with 20 blobs each
    24  	for i := 0; i < 50; i++ {
    25  		packID := restic.NewRandomID()
    26  
    27  		pos := uint(0)
    28  		for j := 0; j < 20; j++ {
    29  			id := restic.NewRandomID()
    30  			length := uint(i*100 + j)
    31  			idx.Store(restic.PackedBlob{
    32  				Blob: restic.Blob{
    33  					Type:   restic.DataBlob,
    34  					ID:     id,
    35  					Offset: pos,
    36  					Length: length,
    37  				},
    38  				PackID: packID,
    39  			})
    40  
    41  			tests = append(tests, testEntry{
    42  				id:     id,
    43  				pack:   packID,
    44  				tpe:    restic.DataBlob,
    45  				offset: pos,
    46  				length: length,
    47  			})
    48  
    49  			pos += length
    50  		}
    51  	}
    52  
    53  	wr := bytes.NewBuffer(nil)
    54  	err := idx.Encode(wr)
    55  	rtest.OK(t, err)
    56  
    57  	idx2, err := repository.DecodeIndex(wr.Bytes())
    58  	rtest.OK(t, err)
    59  	rtest.Assert(t, idx2 != nil,
    60  		"nil returned for decoded index")
    61  
    62  	wr2 := bytes.NewBuffer(nil)
    63  	err = idx2.Encode(wr2)
    64  	rtest.OK(t, err)
    65  
    66  	for _, testBlob := range tests {
    67  		list, err := idx.Lookup(testBlob.id, testBlob.tpe)
    68  		rtest.OK(t, err)
    69  
    70  		if len(list) != 1 {
    71  			t.Errorf("expected one result for blob %v, got %v: %v", testBlob.id.Str(), len(list), list)
    72  		}
    73  		result := list[0]
    74  
    75  		rtest.Equals(t, testBlob.pack, result.PackID)
    76  		rtest.Equals(t, testBlob.tpe, result.Type)
    77  		rtest.Equals(t, testBlob.offset, result.Offset)
    78  		rtest.Equals(t, testBlob.length, result.Length)
    79  
    80  		list2, err := idx2.Lookup(testBlob.id, testBlob.tpe)
    81  		rtest.OK(t, err)
    82  
    83  		if len(list2) != 1 {
    84  			t.Errorf("expected one result for blob %v, got %v: %v", testBlob.id.Str(), len(list2), list2)
    85  		}
    86  		result2 := list2[0]
    87  
    88  		rtest.Equals(t, testBlob.pack, result2.PackID)
    89  		rtest.Equals(t, testBlob.tpe, result2.Type)
    90  		rtest.Equals(t, testBlob.offset, result2.Offset)
    91  		rtest.Equals(t, testBlob.length, result2.Length)
    92  	}
    93  
    94  	// add more blobs to idx
    95  	newtests := []testEntry{}
    96  	for i := 0; i < 10; i++ {
    97  		packID := restic.NewRandomID()
    98  
    99  		pos := uint(0)
   100  		for j := 0; j < 10; j++ {
   101  			id := restic.NewRandomID()
   102  			length := uint(i*100 + j)
   103  			idx.Store(restic.PackedBlob{
   104  				Blob: restic.Blob{
   105  					Type:   restic.DataBlob,
   106  					ID:     id,
   107  					Offset: pos,
   108  					Length: length,
   109  				},
   110  				PackID: packID,
   111  			})
   112  
   113  			newtests = append(newtests, testEntry{
   114  				id:     id,
   115  				pack:   packID,
   116  				tpe:    restic.DataBlob,
   117  				offset: pos,
   118  				length: length,
   119  			})
   120  
   121  			pos += length
   122  		}
   123  	}
   124  
   125  	// serialize idx, unserialize to idx3
   126  	wr3 := bytes.NewBuffer(nil)
   127  	err = idx.Finalize(wr3)
   128  	rtest.OK(t, err)
   129  
   130  	rtest.Assert(t, idx.Final(),
   131  		"index not final after encoding")
   132  
   133  	id := restic.NewRandomID()
   134  	rtest.OK(t, idx.SetID(id))
   135  	id2, err := idx.ID()
   136  	rtest.Assert(t, id2.Equal(id),
   137  		"wrong ID returned: want %v, got %v", id, id2)
   138  
   139  	idx3, err := repository.DecodeIndex(wr3.Bytes())
   140  	rtest.OK(t, err)
   141  	rtest.Assert(t, idx3 != nil,
   142  		"nil returned for decoded index")
   143  	rtest.Assert(t, idx3.Final(),
   144  		"decoded index is not final")
   145  
   146  	// all new blobs must be in the index
   147  	for _, testBlob := range newtests {
   148  		list, err := idx3.Lookup(testBlob.id, testBlob.tpe)
   149  		rtest.OK(t, err)
   150  
   151  		if len(list) != 1 {
   152  			t.Errorf("expected one result for blob %v, got %v: %v", testBlob.id.Str(), len(list), list)
   153  		}
   154  
   155  		blob := list[0]
   156  
   157  		rtest.Equals(t, testBlob.pack, blob.PackID)
   158  		rtest.Equals(t, testBlob.tpe, blob.Type)
   159  		rtest.Equals(t, testBlob.offset, blob.Offset)
   160  		rtest.Equals(t, testBlob.length, blob.Length)
   161  	}
   162  }
   163  
   164  func TestIndexSize(t *testing.T) {
   165  	idx := repository.NewIndex()
   166  
   167  	packs := 200
   168  	blobs := 100
   169  	for i := 0; i < packs; i++ {
   170  		packID := restic.NewRandomID()
   171  
   172  		pos := uint(0)
   173  		for j := 0; j < blobs; j++ {
   174  			id := restic.NewRandomID()
   175  			length := uint(i*100 + j)
   176  			idx.Store(restic.PackedBlob{
   177  				Blob: restic.Blob{
   178  					Type:   restic.DataBlob,
   179  					ID:     id,
   180  					Offset: pos,
   181  					Length: length,
   182  				},
   183  				PackID: packID,
   184  			})
   185  
   186  			pos += length
   187  		}
   188  	}
   189  
   190  	wr := bytes.NewBuffer(nil)
   191  
   192  	err := idx.Encode(wr)
   193  	rtest.OK(t, err)
   194  
   195  	t.Logf("Index file size for %d blobs in %d packs is %d", blobs*packs, packs, wr.Len())
   196  }
   197  
   198  // example index serialization from doc/Design.rst
   199  var docExample = []byte(`
   200  {
   201    "supersedes": [
   202  	"ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452"
   203    ],
   204    "packs": [
   205  	{
   206  	  "id": "73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c",
   207  	  "blobs": [
   208  		{
   209  		  "id": "3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce",
   210  		  "type": "data",
   211  		  "offset": 0,
   212  		  "length": 25
   213  		},{
   214  		  "id": "9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae",
   215  		  "type": "tree",
   216  		  "offset": 38,
   217  		  "length": 100
   218  		},
   219  		{
   220  		  "id": "d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66",
   221  		  "type": "data",
   222  		  "offset": 150,
   223  		  "length": 123
   224  		}
   225  	  ]
   226  	}
   227    ]
   228  }
   229  `)
   230  
   231  var docOldExample = []byte(`
   232  [ {
   233    "id": "73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c",
   234    "blobs": [
   235  	{
   236  	  "id": "3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce",
   237  	  "type": "data",
   238  	  "offset": 0,
   239  	  "length": 25
   240  	},{
   241  	  "id": "9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae",
   242  	  "type": "tree",
   243  	  "offset": 38,
   244  	  "length": 100
   245  	},
   246  	{
   247  	  "id": "d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66",
   248  	  "type": "data",
   249  	  "offset": 150,
   250  	  "length": 123
   251  	}
   252    ]
   253  } ]
   254  `)
   255  
   256  var exampleTests = []struct {
   257  	id, packID     restic.ID
   258  	tpe            restic.BlobType
   259  	offset, length uint
   260  }{
   261  	{
   262  		restic.TestParseID("3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce"),
   263  		restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"),
   264  		restic.DataBlob, 0, 25,
   265  	}, {
   266  		restic.TestParseID("9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae"),
   267  		restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"),
   268  		restic.TreeBlob, 38, 100,
   269  	}, {
   270  		restic.TestParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66"),
   271  		restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"),
   272  		restic.DataBlob, 150, 123,
   273  	},
   274  }
   275  
   276  var exampleLookupTest = struct {
   277  	packID restic.ID
   278  	blobs  map[restic.ID]restic.BlobType
   279  }{
   280  	restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"),
   281  	map[restic.ID]restic.BlobType{
   282  		restic.TestParseID("3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce"): restic.DataBlob,
   283  		restic.TestParseID("9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae"): restic.TreeBlob,
   284  		restic.TestParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66"): restic.DataBlob,
   285  	},
   286  }
   287  
   288  func TestIndexUnserialize(t *testing.T) {
   289  	oldIdx := restic.IDs{restic.TestParseID("ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452")}
   290  
   291  	idx, err := repository.DecodeIndex(docExample)
   292  	rtest.OK(t, err)
   293  
   294  	for _, test := range exampleTests {
   295  		list, err := idx.Lookup(test.id, test.tpe)
   296  		rtest.OK(t, err)
   297  
   298  		if len(list) != 1 {
   299  			t.Errorf("expected one result for blob %v, got %v: %v", test.id.Str(), len(list), list)
   300  		}
   301  		blob := list[0]
   302  
   303  		t.Logf("looking for blob %v/%v, got %v", test.tpe, test.id.Str(), blob)
   304  
   305  		rtest.Equals(t, test.packID, blob.PackID)
   306  		rtest.Equals(t, test.tpe, blob.Type)
   307  		rtest.Equals(t, test.offset, blob.Offset)
   308  		rtest.Equals(t, test.length, blob.Length)
   309  	}
   310  
   311  	rtest.Equals(t, oldIdx, idx.Supersedes())
   312  
   313  	blobs := idx.ListPack(exampleLookupTest.packID)
   314  	if len(blobs) != len(exampleLookupTest.blobs) {
   315  		t.Fatalf("expected %d blobs in pack, got %d", len(exampleLookupTest.blobs), len(blobs))
   316  	}
   317  
   318  	for _, blob := range blobs {
   319  		b, ok := exampleLookupTest.blobs[blob.ID]
   320  		if !ok {
   321  			t.Errorf("unexpected blob %v found", blob.ID.Str())
   322  		}
   323  		if blob.Type != b {
   324  			t.Errorf("unexpected type for blob %v: want %v, got %v", blob.ID.Str(), b, blob.Type)
   325  		}
   326  	}
   327  }
   328  
   329  func BenchmarkDecodeIndex(b *testing.B) {
   330  	b.ResetTimer()
   331  
   332  	for i := 0; i < b.N; i++ {
   333  		_, err := repository.DecodeIndex(docExample)
   334  		rtest.OK(b, err)
   335  	}
   336  }
   337  
   338  func TestIndexUnserializeOld(t *testing.T) {
   339  	idx, err := repository.DecodeOldIndex(docOldExample)
   340  	rtest.OK(t, err)
   341  
   342  	for _, test := range exampleTests {
   343  		list, err := idx.Lookup(test.id, test.tpe)
   344  		rtest.OK(t, err)
   345  
   346  		if len(list) != 1 {
   347  			t.Errorf("expected one result for blob %v, got %v: %v", test.id.Str(), len(list), list)
   348  		}
   349  		blob := list[0]
   350  
   351  		rtest.Equals(t, test.packID, blob.PackID)
   352  		rtest.Equals(t, test.tpe, blob.Type)
   353  		rtest.Equals(t, test.offset, blob.Offset)
   354  		rtest.Equals(t, test.length, blob.Length)
   355  	}
   356  
   357  	rtest.Equals(t, 0, len(idx.Supersedes()))
   358  }
   359  
   360  func TestIndexPacks(t *testing.T) {
   361  	idx := repository.NewIndex()
   362  	packs := restic.NewIDSet()
   363  
   364  	for i := 0; i < 20; i++ {
   365  		packID := restic.NewRandomID()
   366  		idx.Store(restic.PackedBlob{
   367  			Blob: restic.Blob{
   368  				Type:   restic.DataBlob,
   369  				ID:     restic.NewRandomID(),
   370  				Offset: 0,
   371  				Length: 23,
   372  			},
   373  			PackID: packID,
   374  		})
   375  
   376  		packs.Insert(packID)
   377  	}
   378  
   379  	idxPacks := idx.Packs()
   380  	rtest.Assert(t, packs.Equals(idxPacks), "packs in index do not match packs added to index")
   381  }