go.etcd.io/etcd@v3.3.27+incompatible/mvcc/key_index_test.go (about)

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mvcc
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  )
    21  
    22  func TestKeyIndexGet(t *testing.T) {
    23  	// key: "foo"
    24  	// rev: 16
    25  	// generations:
    26  	//    {empty}
    27  	//    {{14, 0}[1], {14, 1}[2], {16, 0}(t)[3]}
    28  	//    {{8, 0}[1], {10, 0}[2], {12, 0}(t)[3]}
    29  	//    {{2, 0}[1], {4, 0}[2], {6, 0}(t)[3]}
    30  	ki := newTestKeyIndex()
    31  	ki.compact(4, make(map[revision]struct{}))
    32  
    33  	tests := []struct {
    34  		rev int64
    35  
    36  		wmod   revision
    37  		wcreat revision
    38  		wver   int64
    39  		werr   error
    40  	}{
    41  		{17, revision{}, revision{}, 0, ErrRevisionNotFound},
    42  		{16, revision{}, revision{}, 0, ErrRevisionNotFound},
    43  
    44  		// get on generation 3
    45  		{15, revision{14, 1}, revision{14, 0}, 2, nil},
    46  		{14, revision{14, 1}, revision{14, 0}, 2, nil},
    47  
    48  		{13, revision{}, revision{}, 0, ErrRevisionNotFound},
    49  		{12, revision{}, revision{}, 0, ErrRevisionNotFound},
    50  
    51  		// get on generation 2
    52  		{11, revision{10, 0}, revision{8, 0}, 2, nil},
    53  		{10, revision{10, 0}, revision{8, 0}, 2, nil},
    54  		{9, revision{8, 0}, revision{8, 0}, 1, nil},
    55  		{8, revision{8, 0}, revision{8, 0}, 1, nil},
    56  
    57  		{7, revision{}, revision{}, 0, ErrRevisionNotFound},
    58  		{6, revision{}, revision{}, 0, ErrRevisionNotFound},
    59  
    60  		// get on generation 1
    61  		{5, revision{4, 0}, revision{2, 0}, 2, nil},
    62  		{4, revision{4, 0}, revision{2, 0}, 2, nil},
    63  
    64  		{3, revision{}, revision{}, 0, ErrRevisionNotFound},
    65  		{2, revision{}, revision{}, 0, ErrRevisionNotFound},
    66  		{1, revision{}, revision{}, 0, ErrRevisionNotFound},
    67  		{0, revision{}, revision{}, 0, ErrRevisionNotFound},
    68  	}
    69  
    70  	for i, tt := range tests {
    71  		mod, creat, ver, err := ki.get(tt.rev)
    72  		if err != tt.werr {
    73  			t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
    74  		}
    75  		if mod != tt.wmod {
    76  			t.Errorf("#%d: modified = %+v, want %+v", i, mod, tt.wmod)
    77  		}
    78  		if creat != tt.wcreat {
    79  			t.Errorf("#%d: created = %+v, want %+v", i, creat, tt.wcreat)
    80  		}
    81  		if ver != tt.wver {
    82  			t.Errorf("#%d: version = %d, want %d", i, ver, tt.wver)
    83  		}
    84  	}
    85  }
    86  
    87  func TestKeyIndexSince(t *testing.T) {
    88  	ki := newTestKeyIndex()
    89  	ki.compact(4, make(map[revision]struct{}))
    90  
    91  	allRevs := []revision{{4, 0}, {6, 0}, {8, 0}, {10, 0}, {12, 0}, {14, 1}, {16, 0}}
    92  	tests := []struct {
    93  		rev int64
    94  
    95  		wrevs []revision
    96  	}{
    97  		{17, nil},
    98  		{16, allRevs[6:]},
    99  		{15, allRevs[6:]},
   100  		{14, allRevs[5:]},
   101  		{13, allRevs[5:]},
   102  		{12, allRevs[4:]},
   103  		{11, allRevs[4:]},
   104  		{10, allRevs[3:]},
   105  		{9, allRevs[3:]},
   106  		{8, allRevs[2:]},
   107  		{7, allRevs[2:]},
   108  		{6, allRevs[1:]},
   109  		{5, allRevs[1:]},
   110  		{4, allRevs},
   111  		{3, allRevs},
   112  		{2, allRevs},
   113  		{1, allRevs},
   114  		{0, allRevs},
   115  	}
   116  
   117  	for i, tt := range tests {
   118  		revs := ki.since(tt.rev)
   119  		if !reflect.DeepEqual(revs, tt.wrevs) {
   120  			t.Errorf("#%d: revs = %+v, want %+v", i, revs, tt.wrevs)
   121  		}
   122  	}
   123  }
   124  
   125  func TestKeyIndexPut(t *testing.T) {
   126  	ki := &keyIndex{key: []byte("foo")}
   127  	ki.put(5, 0)
   128  
   129  	wki := &keyIndex{
   130  		key:         []byte("foo"),
   131  		modified:    revision{5, 0},
   132  		generations: []generation{{created: revision{5, 0}, ver: 1, revs: []revision{{main: 5}}}},
   133  	}
   134  	if !reflect.DeepEqual(ki, wki) {
   135  		t.Errorf("ki = %+v, want %+v", ki, wki)
   136  	}
   137  
   138  	ki.put(7, 0)
   139  
   140  	wki = &keyIndex{
   141  		key:         []byte("foo"),
   142  		modified:    revision{7, 0},
   143  		generations: []generation{{created: revision{5, 0}, ver: 2, revs: []revision{{main: 5}, {main: 7}}}},
   144  	}
   145  	if !reflect.DeepEqual(ki, wki) {
   146  		t.Errorf("ki = %+v, want %+v", ki, wki)
   147  	}
   148  }
   149  
   150  func TestKeyIndexRestore(t *testing.T) {
   151  	ki := &keyIndex{key: []byte("foo")}
   152  	ki.restore(revision{5, 0}, revision{7, 0}, 2)
   153  
   154  	wki := &keyIndex{
   155  		key:         []byte("foo"),
   156  		modified:    revision{7, 0},
   157  		generations: []generation{{created: revision{5, 0}, ver: 2, revs: []revision{{main: 7}}}},
   158  	}
   159  	if !reflect.DeepEqual(ki, wki) {
   160  		t.Errorf("ki = %+v, want %+v", ki, wki)
   161  	}
   162  }
   163  
   164  func TestKeyIndexTombstone(t *testing.T) {
   165  	ki := &keyIndex{key: []byte("foo")}
   166  	ki.put(5, 0)
   167  
   168  	err := ki.tombstone(7, 0)
   169  	if err != nil {
   170  		t.Errorf("unexpected tombstone error: %v", err)
   171  	}
   172  
   173  	wki := &keyIndex{
   174  		key:         []byte("foo"),
   175  		modified:    revision{7, 0},
   176  		generations: []generation{{created: revision{5, 0}, ver: 2, revs: []revision{{main: 5}, {main: 7}}}, {}},
   177  	}
   178  	if !reflect.DeepEqual(ki, wki) {
   179  		t.Errorf("ki = %+v, want %+v", ki, wki)
   180  	}
   181  
   182  	ki.put(8, 0)
   183  	ki.put(9, 0)
   184  	err = ki.tombstone(15, 0)
   185  	if err != nil {
   186  		t.Errorf("unexpected tombstone error: %v", err)
   187  	}
   188  
   189  	wki = &keyIndex{
   190  		key:      []byte("foo"),
   191  		modified: revision{15, 0},
   192  		generations: []generation{
   193  			{created: revision{5, 0}, ver: 2, revs: []revision{{main: 5}, {main: 7}}},
   194  			{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 9}, {main: 15}}},
   195  			{},
   196  		},
   197  	}
   198  	if !reflect.DeepEqual(ki, wki) {
   199  		t.Errorf("ki = %+v, want %+v", ki, wki)
   200  	}
   201  
   202  	err = ki.tombstone(16, 0)
   203  	if err != ErrRevisionNotFound {
   204  		t.Errorf("tombstone error = %v, want %v", err, ErrRevisionNotFound)
   205  	}
   206  }
   207  
   208  func TestKeyIndexCompactAndKeep(t *testing.T) {
   209  	tests := []struct {
   210  		compact int64
   211  
   212  		wki *keyIndex
   213  		wam map[revision]struct{}
   214  	}{
   215  		{
   216  			1,
   217  			&keyIndex{
   218  				key:      []byte("foo"),
   219  				modified: revision{16, 0},
   220  				generations: []generation{
   221  					{created: revision{2, 0}, ver: 3, revs: []revision{{main: 2}, {main: 4}, {main: 6}}},
   222  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   223  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   224  					{},
   225  				},
   226  			},
   227  			map[revision]struct{}{},
   228  		},
   229  		{
   230  			2,
   231  			&keyIndex{
   232  				key:      []byte("foo"),
   233  				modified: revision{16, 0},
   234  				generations: []generation{
   235  					{created: revision{2, 0}, ver: 3, revs: []revision{{main: 2}, {main: 4}, {main: 6}}},
   236  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   237  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   238  					{},
   239  				},
   240  			},
   241  			map[revision]struct{}{
   242  				{main: 2}: {},
   243  			},
   244  		},
   245  		{
   246  			3,
   247  			&keyIndex{
   248  				key:      []byte("foo"),
   249  				modified: revision{16, 0},
   250  				generations: []generation{
   251  					{created: revision{2, 0}, ver: 3, revs: []revision{{main: 2}, {main: 4}, {main: 6}}},
   252  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   253  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   254  					{},
   255  				},
   256  			},
   257  			map[revision]struct{}{
   258  				{main: 2}: {},
   259  			},
   260  		},
   261  		{
   262  			4,
   263  			&keyIndex{
   264  				key:      []byte("foo"),
   265  				modified: revision{16, 0},
   266  				generations: []generation{
   267  					{created: revision{2, 0}, ver: 3, revs: []revision{{main: 4}, {main: 6}}},
   268  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   269  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   270  					{},
   271  				},
   272  			},
   273  			map[revision]struct{}{
   274  				{main: 4}: {},
   275  			},
   276  		},
   277  		{
   278  			5,
   279  			&keyIndex{
   280  				key:      []byte("foo"),
   281  				modified: revision{16, 0},
   282  				generations: []generation{
   283  					{created: revision{2, 0}, ver: 3, revs: []revision{{main: 4}, {main: 6}}},
   284  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   285  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   286  					{},
   287  				},
   288  			},
   289  			map[revision]struct{}{
   290  				{main: 4}: {},
   291  			},
   292  		},
   293  		{
   294  			6,
   295  			&keyIndex{
   296  				key:      []byte("foo"),
   297  				modified: revision{16, 0},
   298  				generations: []generation{
   299  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   300  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   301  					{},
   302  				},
   303  			},
   304  			map[revision]struct{}{},
   305  		},
   306  		{
   307  			7,
   308  			&keyIndex{
   309  				key:      []byte("foo"),
   310  				modified: revision{16, 0},
   311  				generations: []generation{
   312  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   313  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   314  					{},
   315  				},
   316  			},
   317  			map[revision]struct{}{},
   318  		},
   319  		{
   320  			8,
   321  			&keyIndex{
   322  				key:      []byte("foo"),
   323  				modified: revision{16, 0},
   324  				generations: []generation{
   325  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   326  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   327  					{},
   328  				},
   329  			},
   330  			map[revision]struct{}{
   331  				{main: 8}: {},
   332  			},
   333  		},
   334  		{
   335  			9,
   336  			&keyIndex{
   337  				key:      []byte("foo"),
   338  				modified: revision{16, 0},
   339  				generations: []generation{
   340  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 8}, {main: 10}, {main: 12}}},
   341  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   342  					{},
   343  				},
   344  			},
   345  			map[revision]struct{}{
   346  				{main: 8}: {},
   347  			},
   348  		},
   349  		{
   350  			10,
   351  			&keyIndex{
   352  				key:      []byte("foo"),
   353  				modified: revision{16, 0},
   354  				generations: []generation{
   355  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 10}, {main: 12}}},
   356  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   357  					{},
   358  				},
   359  			},
   360  			map[revision]struct{}{
   361  				{main: 10}: {},
   362  			},
   363  		},
   364  		{
   365  			11,
   366  			&keyIndex{
   367  				key:      []byte("foo"),
   368  				modified: revision{16, 0},
   369  				generations: []generation{
   370  					{created: revision{8, 0}, ver: 3, revs: []revision{{main: 10}, {main: 12}}},
   371  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   372  					{},
   373  				},
   374  			},
   375  			map[revision]struct{}{
   376  				{main: 10}: {},
   377  			},
   378  		},
   379  		{
   380  			12,
   381  			&keyIndex{
   382  				key:      []byte("foo"),
   383  				modified: revision{16, 0},
   384  				generations: []generation{
   385  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   386  					{},
   387  				},
   388  			},
   389  			map[revision]struct{}{},
   390  		},
   391  		{
   392  			13,
   393  			&keyIndex{
   394  				key:      []byte("foo"),
   395  				modified: revision{16, 0},
   396  				generations: []generation{
   397  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14}, {main: 14, sub: 1}, {main: 16}}},
   398  					{},
   399  				},
   400  			},
   401  			map[revision]struct{}{},
   402  		},
   403  		{
   404  			14,
   405  			&keyIndex{
   406  				key:      []byte("foo"),
   407  				modified: revision{16, 0},
   408  				generations: []generation{
   409  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14, sub: 1}, {main: 16}}},
   410  					{},
   411  				},
   412  			},
   413  			map[revision]struct{}{
   414  				{main: 14, sub: 1}: {},
   415  			},
   416  		},
   417  		{
   418  			15,
   419  			&keyIndex{
   420  				key:      []byte("foo"),
   421  				modified: revision{16, 0},
   422  				generations: []generation{
   423  					{created: revision{14, 0}, ver: 3, revs: []revision{{main: 14, sub: 1}, {main: 16}}},
   424  					{},
   425  				},
   426  			},
   427  			map[revision]struct{}{
   428  				{main: 14, sub: 1}: {},
   429  			},
   430  		},
   431  		{
   432  			16,
   433  			&keyIndex{
   434  				key:      []byte("foo"),
   435  				modified: revision{16, 0},
   436  				generations: []generation{
   437  					{},
   438  				},
   439  			},
   440  			map[revision]struct{}{},
   441  		},
   442  	}
   443  
   444  	// Continuous Compaction and finding Keep
   445  	ki := newTestKeyIndex()
   446  	for i, tt := range tests {
   447  		am := make(map[revision]struct{})
   448  		kiclone := cloneKeyIndex(ki)
   449  		ki.keep(tt.compact, am)
   450  		if !reflect.DeepEqual(ki, kiclone) {
   451  			t.Errorf("#%d: ki = %+v, want %+v", i, ki, kiclone)
   452  		}
   453  		if !reflect.DeepEqual(am, tt.wam) {
   454  			t.Errorf("#%d: am = %+v, want %+v", i, am, tt.wam)
   455  		}
   456  		am = make(map[revision]struct{})
   457  		ki.compact(tt.compact, am)
   458  		if !reflect.DeepEqual(ki, tt.wki) {
   459  			t.Errorf("#%d: ki = %+v, want %+v", i, ki, tt.wki)
   460  		}
   461  		if !reflect.DeepEqual(am, tt.wam) {
   462  			t.Errorf("#%d: am = %+v, want %+v", i, am, tt.wam)
   463  		}
   464  	}
   465  
   466  	// Jump Compaction and finding Keep
   467  	ki = newTestKeyIndex()
   468  	for i, tt := range tests {
   469  		if (i%2 == 0 && i < 6) || (i%2 == 1 && i > 6) {
   470  			am := make(map[revision]struct{})
   471  			kiclone := cloneKeyIndex(ki)
   472  			ki.keep(tt.compact, am)
   473  			if !reflect.DeepEqual(ki, kiclone) {
   474  				t.Errorf("#%d: ki = %+v, want %+v", i, ki, kiclone)
   475  			}
   476  			if !reflect.DeepEqual(am, tt.wam) {
   477  				t.Errorf("#%d: am = %+v, want %+v", i, am, tt.wam)
   478  			}
   479  			am = make(map[revision]struct{})
   480  			ki.compact(tt.compact, am)
   481  			if !reflect.DeepEqual(ki, tt.wki) {
   482  				t.Errorf("#%d: ki = %+v, want %+v", i, ki, tt.wki)
   483  			}
   484  			if !reflect.DeepEqual(am, tt.wam) {
   485  				t.Errorf("#%d: am = %+v, want %+v", i, am, tt.wam)
   486  			}
   487  		}
   488  	}
   489  
   490  	kiClone := newTestKeyIndex()
   491  	// Once Compaction and finding Keep
   492  	for i, tt := range tests {
   493  		ki := newTestKeyIndex()
   494  		am := make(map[revision]struct{})
   495  		ki.keep(tt.compact, am)
   496  		if !reflect.DeepEqual(ki, kiClone) {
   497  			t.Errorf("#%d: ki = %+v, want %+v", i, ki, kiClone)
   498  		}
   499  		if !reflect.DeepEqual(am, tt.wam) {
   500  			t.Errorf("#%d: am = %+v, want %+v", i, am, tt.wam)
   501  		}
   502  		am = make(map[revision]struct{})
   503  		ki.compact(tt.compact, am)
   504  		if !reflect.DeepEqual(ki, tt.wki) {
   505  			t.Errorf("#%d: ki = %+v, want %+v", i, ki, tt.wki)
   506  		}
   507  		if !reflect.DeepEqual(am, tt.wam) {
   508  			t.Errorf("#%d: am = %+v, want %+v", i, am, tt.wam)
   509  		}
   510  	}
   511  }
   512  
   513  func cloneKeyIndex(ki *keyIndex) *keyIndex {
   514  	generations := make([]generation, len(ki.generations))
   515  	for i, gen := range ki.generations {
   516  		generations[i] = *cloneGeneration(&gen)
   517  	}
   518  	return &keyIndex{ki.key, ki.modified, generations}
   519  }
   520  
   521  func cloneGeneration(g *generation) *generation {
   522  	if g.revs == nil {
   523  		return &generation{g.ver, g.created, nil}
   524  	}
   525  	tmp := make([]revision, len(g.revs))
   526  	copy(tmp, g.revs)
   527  	return &generation{g.ver, g.created, tmp}
   528  }
   529  
   530  // test that compact on version that higher than last modified version works well
   531  func TestKeyIndexCompactOnFurtherRev(t *testing.T) {
   532  	ki := &keyIndex{key: []byte("foo")}
   533  	ki.put(1, 0)
   534  	ki.put(2, 0)
   535  	am := make(map[revision]struct{})
   536  	ki.compact(3, am)
   537  
   538  	wki := &keyIndex{
   539  		key:      []byte("foo"),
   540  		modified: revision{2, 0},
   541  		generations: []generation{
   542  			{created: revision{1, 0}, ver: 2, revs: []revision{{main: 2}}},
   543  		},
   544  	}
   545  	wam := map[revision]struct{}{
   546  		{main: 2}: {},
   547  	}
   548  	if !reflect.DeepEqual(ki, wki) {
   549  		t.Errorf("ki = %+v, want %+v", ki, wki)
   550  	}
   551  	if !reflect.DeepEqual(am, wam) {
   552  		t.Errorf("am = %+v, want %+v", am, wam)
   553  	}
   554  }
   555  
   556  func TestKeyIndexIsEmpty(t *testing.T) {
   557  	tests := []struct {
   558  		ki *keyIndex
   559  		w  bool
   560  	}{
   561  		{
   562  			&keyIndex{
   563  				key:         []byte("foo"),
   564  				generations: []generation{{}},
   565  			},
   566  			true,
   567  		},
   568  		{
   569  			&keyIndex{
   570  				key:      []byte("foo"),
   571  				modified: revision{2, 0},
   572  				generations: []generation{
   573  					{created: revision{1, 0}, ver: 2, revs: []revision{{main: 2}}},
   574  				},
   575  			},
   576  			false,
   577  		},
   578  	}
   579  	for i, tt := range tests {
   580  		g := tt.ki.isEmpty()
   581  		if g != tt.w {
   582  			t.Errorf("#%d: isEmpty = %v, want %v", i, g, tt.w)
   583  		}
   584  	}
   585  }
   586  
   587  func TestKeyIndexFindGeneration(t *testing.T) {
   588  	ki := newTestKeyIndex()
   589  
   590  	tests := []struct {
   591  		rev int64
   592  		wg  *generation
   593  	}{
   594  		{0, nil},
   595  		{1, nil},
   596  		{2, &ki.generations[0]},
   597  		{3, &ki.generations[0]},
   598  		{4, &ki.generations[0]},
   599  		{5, &ki.generations[0]},
   600  		{6, nil},
   601  		{7, nil},
   602  		{8, &ki.generations[1]},
   603  		{9, &ki.generations[1]},
   604  		{10, &ki.generations[1]},
   605  		{11, &ki.generations[1]},
   606  		{12, nil},
   607  		{13, nil},
   608  	}
   609  	for i, tt := range tests {
   610  		g := ki.findGeneration(tt.rev)
   611  		if g != tt.wg {
   612  			t.Errorf("#%d: generation = %+v, want %+v", i, g, tt.wg)
   613  		}
   614  	}
   615  }
   616  
   617  func TestKeyIndexLess(t *testing.T) {
   618  	ki := &keyIndex{key: []byte("foo")}
   619  
   620  	tests := []struct {
   621  		ki *keyIndex
   622  		w  bool
   623  	}{
   624  		{&keyIndex{key: []byte("doo")}, false},
   625  		{&keyIndex{key: []byte("foo")}, false},
   626  		{&keyIndex{key: []byte("goo")}, true},
   627  	}
   628  	for i, tt := range tests {
   629  		g := ki.Less(tt.ki)
   630  		if g != tt.w {
   631  			t.Errorf("#%d: Less = %v, want %v", i, g, tt.w)
   632  		}
   633  	}
   634  }
   635  
   636  func TestGenerationIsEmpty(t *testing.T) {
   637  	tests := []struct {
   638  		g *generation
   639  		w bool
   640  	}{
   641  		{nil, true},
   642  		{&generation{}, true},
   643  		{&generation{revs: []revision{{main: 1}}}, false},
   644  	}
   645  	for i, tt := range tests {
   646  		g := tt.g.isEmpty()
   647  		if g != tt.w {
   648  			t.Errorf("#%d: isEmpty = %v, want %v", i, g, tt.w)
   649  		}
   650  	}
   651  }
   652  
   653  func TestGenerationWalk(t *testing.T) {
   654  	g := &generation{
   655  		ver:     3,
   656  		created: revision{2, 0},
   657  		revs:    []revision{{main: 2}, {main: 4}, {main: 6}},
   658  	}
   659  	tests := []struct {
   660  		f  func(rev revision) bool
   661  		wi int
   662  	}{
   663  		{func(rev revision) bool { return rev.main >= 7 }, 2},
   664  		{func(rev revision) bool { return rev.main >= 6 }, 1},
   665  		{func(rev revision) bool { return rev.main >= 5 }, 1},
   666  		{func(rev revision) bool { return rev.main >= 4 }, 0},
   667  		{func(rev revision) bool { return rev.main >= 3 }, 0},
   668  		{func(rev revision) bool { return rev.main >= 2 }, -1},
   669  	}
   670  	for i, tt := range tests {
   671  		idx := g.walk(tt.f)
   672  		if idx != tt.wi {
   673  			t.Errorf("#%d: index = %d, want %d", i, idx, tt.wi)
   674  		}
   675  	}
   676  }
   677  
   678  func newTestKeyIndex() *keyIndex {
   679  	// key: "foo"
   680  	// rev: 16
   681  	// generations:
   682  	//    {empty}
   683  	//    {{14, 0}[1], {14, 1}[2], {16, 0}(t)[3]}
   684  	//    {{8, 0}[1], {10, 0}[2], {12, 0}(t)[3]}
   685  	//    {{2, 0}[1], {4, 0}[2], {6, 0}(t)[3]}
   686  
   687  	ki := &keyIndex{key: []byte("foo")}
   688  	ki.put(2, 0)
   689  	ki.put(4, 0)
   690  	ki.tombstone(6, 0)
   691  	ki.put(8, 0)
   692  	ki.put(10, 0)
   693  	ki.tombstone(12, 0)
   694  	ki.put(14, 0)
   695  	ki.put(14, 1)
   696  	ki.tombstone(16, 0)
   697  	return ki
   698  }