github.com/olljanat/moby@v1.13.1/pkg/truncindex/truncindex_test.go (about)

     1  package truncindex
     2  
     3  import (
     4  	"math/rand"
     5  	"testing"
     6  
     7  	"github.com/docker/docker/pkg/stringid"
     8  )
     9  
    10  // Test the behavior of TruncIndex, an index for querying IDs from a non-conflicting prefix.
    11  func TestTruncIndex(t *testing.T) {
    12  	ids := []string{}
    13  	index := NewTruncIndex(ids)
    14  	// Get on an empty index
    15  	if _, err := index.Get("foobar"); err == nil {
    16  		t.Fatal("Get on an empty index should return an error")
    17  	}
    18  
    19  	// Spaces should be illegal in an id
    20  	if err := index.Add("I have a space"); err == nil {
    21  		t.Fatalf("Adding an id with ' ' should return an error")
    22  	}
    23  
    24  	id := "99b36c2c326ccc11e726eee6ee78a0baf166ef96"
    25  	// Add an id
    26  	if err := index.Add(id); err != nil {
    27  		t.Fatal(err)
    28  	}
    29  
    30  	// Add an empty id (should fail)
    31  	if err := index.Add(""); err == nil {
    32  		t.Fatalf("Adding an empty id should return an error")
    33  	}
    34  
    35  	// Get a non-existing id
    36  	assertIndexGet(t, index, "abracadabra", "", true)
    37  	// Get an empty id
    38  	assertIndexGet(t, index, "", "", true)
    39  	// Get the exact id
    40  	assertIndexGet(t, index, id, id, false)
    41  	// The first letter should match
    42  	assertIndexGet(t, index, id[:1], id, false)
    43  	// The first half should match
    44  	assertIndexGet(t, index, id[:len(id)/2], id, false)
    45  	// The second half should NOT match
    46  	assertIndexGet(t, index, id[len(id)/2:], "", true)
    47  
    48  	id2 := id[:6] + "blabla"
    49  	// Add an id
    50  	if err := index.Add(id2); err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	// Both exact IDs should work
    54  	assertIndexGet(t, index, id, id, false)
    55  	assertIndexGet(t, index, id2, id2, false)
    56  
    57  	// 6 characters or less should conflict
    58  	assertIndexGet(t, index, id[:6], "", true)
    59  	assertIndexGet(t, index, id[:4], "", true)
    60  	assertIndexGet(t, index, id[:1], "", true)
    61  
    62  	// An ambiguous id prefix should return an error
    63  	if _, err := index.Get(id[:4]); err == nil {
    64  		t.Fatal("An ambiguous id prefix should return an error")
    65  	}
    66  
    67  	// 7 characters should NOT conflict
    68  	assertIndexGet(t, index, id[:7], id, false)
    69  	assertIndexGet(t, index, id2[:7], id2, false)
    70  
    71  	// Deleting a non-existing id should return an error
    72  	if err := index.Delete("non-existing"); err == nil {
    73  		t.Fatalf("Deleting a non-existing id should return an error")
    74  	}
    75  
    76  	// Deleting an empty id should return an error
    77  	if err := index.Delete(""); err == nil {
    78  		t.Fatal("Deleting an empty id should return an error")
    79  	}
    80  
    81  	// Deleting id2 should remove conflicts
    82  	if err := index.Delete(id2); err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	// id2 should no longer work
    86  	assertIndexGet(t, index, id2, "", true)
    87  	assertIndexGet(t, index, id2[:7], "", true)
    88  	assertIndexGet(t, index, id2[:11], "", true)
    89  
    90  	// conflicts between id and id2 should be gone
    91  	assertIndexGet(t, index, id[:6], id, false)
    92  	assertIndexGet(t, index, id[:4], id, false)
    93  	assertIndexGet(t, index, id[:1], id, false)
    94  
    95  	// non-conflicting substrings should still not conflict
    96  	assertIndexGet(t, index, id[:7], id, false)
    97  	assertIndexGet(t, index, id[:15], id, false)
    98  	assertIndexGet(t, index, id, id, false)
    99  
   100  	assertIndexIterate(t)
   101  }
   102  
   103  func assertIndexIterate(t *testing.T) {
   104  	ids := []string{
   105  		"19b36c2c326ccc11e726eee6ee78a0baf166ef96",
   106  		"28b36c2c326ccc11e726eee6ee78a0baf166ef96",
   107  		"37b36c2c326ccc11e726eee6ee78a0baf166ef96",
   108  		"46b36c2c326ccc11e726eee6ee78a0baf166ef96",
   109  	}
   110  
   111  	index := NewTruncIndex(ids)
   112  
   113  	index.Iterate(func(targetId string) {
   114  		for _, id := range ids {
   115  			if targetId == id {
   116  				return
   117  			}
   118  		}
   119  
   120  		t.Fatalf("An unknown ID '%s'", targetId)
   121  	})
   122  }
   123  
   124  func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {
   125  	if result, err := index.Get(input); err != nil && !expectError {
   126  		t.Fatalf("Unexpected error getting '%s': %s", input, err)
   127  	} else if err == nil && expectError {
   128  		t.Fatalf("Getting '%s' should return an error, not '%s'", input, result)
   129  	} else if result != expectedResult {
   130  		t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
   131  	}
   132  }
   133  
   134  func BenchmarkTruncIndexAdd100(b *testing.B) {
   135  	var testSet []string
   136  	for i := 0; i < 100; i++ {
   137  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   138  	}
   139  	b.ResetTimer()
   140  	for i := 0; i < b.N; i++ {
   141  		index := NewTruncIndex([]string{})
   142  		for _, id := range testSet {
   143  			if err := index.Add(id); err != nil {
   144  				b.Fatal(err)
   145  			}
   146  		}
   147  	}
   148  }
   149  
   150  func BenchmarkTruncIndexAdd250(b *testing.B) {
   151  	var testSet []string
   152  	for i := 0; i < 250; i++ {
   153  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   154  	}
   155  	b.ResetTimer()
   156  	for i := 0; i < b.N; i++ {
   157  		index := NewTruncIndex([]string{})
   158  		for _, id := range testSet {
   159  			if err := index.Add(id); err != nil {
   160  				b.Fatal(err)
   161  			}
   162  		}
   163  	}
   164  }
   165  
   166  func BenchmarkTruncIndexAdd500(b *testing.B) {
   167  	var testSet []string
   168  	for i := 0; i < 500; i++ {
   169  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   170  	}
   171  	b.ResetTimer()
   172  	for i := 0; i < b.N; i++ {
   173  		index := NewTruncIndex([]string{})
   174  		for _, id := range testSet {
   175  			if err := index.Add(id); err != nil {
   176  				b.Fatal(err)
   177  			}
   178  		}
   179  	}
   180  }
   181  
   182  func BenchmarkTruncIndexGet100(b *testing.B) {
   183  	var testSet []string
   184  	var testKeys []string
   185  	for i := 0; i < 100; i++ {
   186  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   187  	}
   188  	index := NewTruncIndex([]string{})
   189  	for _, id := range testSet {
   190  		if err := index.Add(id); err != nil {
   191  			b.Fatal(err)
   192  		}
   193  		l := rand.Intn(12) + 12
   194  		testKeys = append(testKeys, id[:l])
   195  	}
   196  	b.ResetTimer()
   197  	for i := 0; i < b.N; i++ {
   198  		for _, id := range testKeys {
   199  			if res, err := index.Get(id); err != nil {
   200  				b.Fatal(res, err)
   201  			}
   202  		}
   203  	}
   204  }
   205  
   206  func BenchmarkTruncIndexGet250(b *testing.B) {
   207  	var testSet []string
   208  	var testKeys []string
   209  	for i := 0; i < 250; i++ {
   210  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   211  	}
   212  	index := NewTruncIndex([]string{})
   213  	for _, id := range testSet {
   214  		if err := index.Add(id); err != nil {
   215  			b.Fatal(err)
   216  		}
   217  		l := rand.Intn(12) + 12
   218  		testKeys = append(testKeys, id[:l])
   219  	}
   220  	b.ResetTimer()
   221  	for i := 0; i < b.N; i++ {
   222  		for _, id := range testKeys {
   223  			if res, err := index.Get(id); err != nil {
   224  				b.Fatal(res, err)
   225  			}
   226  		}
   227  	}
   228  }
   229  
   230  func BenchmarkTruncIndexGet500(b *testing.B) {
   231  	var testSet []string
   232  	var testKeys []string
   233  	for i := 0; i < 500; i++ {
   234  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   235  	}
   236  	index := NewTruncIndex([]string{})
   237  	for _, id := range testSet {
   238  		if err := index.Add(id); err != nil {
   239  			b.Fatal(err)
   240  		}
   241  		l := rand.Intn(12) + 12
   242  		testKeys = append(testKeys, id[:l])
   243  	}
   244  	b.ResetTimer()
   245  	for i := 0; i < b.N; i++ {
   246  		for _, id := range testKeys {
   247  			if res, err := index.Get(id); err != nil {
   248  				b.Fatal(res, err)
   249  			}
   250  		}
   251  	}
   252  }
   253  
   254  func BenchmarkTruncIndexDelete100(b *testing.B) {
   255  	var testSet []string
   256  	for i := 0; i < 100; i++ {
   257  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   258  	}
   259  	b.ResetTimer()
   260  	for i := 0; i < b.N; i++ {
   261  		b.StopTimer()
   262  		index := NewTruncIndex([]string{})
   263  		for _, id := range testSet {
   264  			if err := index.Add(id); err != nil {
   265  				b.Fatal(err)
   266  			}
   267  		}
   268  		b.StartTimer()
   269  		for _, id := range testSet {
   270  			if err := index.Delete(id); err != nil {
   271  				b.Fatal(err)
   272  			}
   273  		}
   274  	}
   275  }
   276  
   277  func BenchmarkTruncIndexDelete250(b *testing.B) {
   278  	var testSet []string
   279  	for i := 0; i < 250; i++ {
   280  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   281  	}
   282  	b.ResetTimer()
   283  	for i := 0; i < b.N; i++ {
   284  		b.StopTimer()
   285  		index := NewTruncIndex([]string{})
   286  		for _, id := range testSet {
   287  			if err := index.Add(id); err != nil {
   288  				b.Fatal(err)
   289  			}
   290  		}
   291  		b.StartTimer()
   292  		for _, id := range testSet {
   293  			if err := index.Delete(id); err != nil {
   294  				b.Fatal(err)
   295  			}
   296  		}
   297  	}
   298  }
   299  
   300  func BenchmarkTruncIndexDelete500(b *testing.B) {
   301  	var testSet []string
   302  	for i := 0; i < 500; i++ {
   303  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   304  	}
   305  	b.ResetTimer()
   306  	for i := 0; i < b.N; i++ {
   307  		b.StopTimer()
   308  		index := NewTruncIndex([]string{})
   309  		for _, id := range testSet {
   310  			if err := index.Add(id); err != nil {
   311  				b.Fatal(err)
   312  			}
   313  		}
   314  		b.StartTimer()
   315  		for _, id := range testSet {
   316  			if err := index.Delete(id); err != nil {
   317  				b.Fatal(err)
   318  			}
   319  		}
   320  	}
   321  }
   322  
   323  func BenchmarkTruncIndexNew100(b *testing.B) {
   324  	var testSet []string
   325  	for i := 0; i < 100; i++ {
   326  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   327  	}
   328  	b.ResetTimer()
   329  	for i := 0; i < b.N; i++ {
   330  		NewTruncIndex(testSet)
   331  	}
   332  }
   333  
   334  func BenchmarkTruncIndexNew250(b *testing.B) {
   335  	var testSet []string
   336  	for i := 0; i < 250; i++ {
   337  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   338  	}
   339  	b.ResetTimer()
   340  	for i := 0; i < b.N; i++ {
   341  		NewTruncIndex(testSet)
   342  	}
   343  }
   344  
   345  func BenchmarkTruncIndexNew500(b *testing.B) {
   346  	var testSet []string
   347  	for i := 0; i < 500; i++ {
   348  		testSet = append(testSet, stringid.GenerateNonCryptoID())
   349  	}
   350  	b.ResetTimer()
   351  	for i := 0; i < b.N; i++ {
   352  		NewTruncIndex(testSet)
   353  	}
   354  }
   355  
   356  func BenchmarkTruncIndexAddGet100(b *testing.B) {
   357  	var testSet []string
   358  	var testKeys []string
   359  	for i := 0; i < 500; i++ {
   360  		id := stringid.GenerateNonCryptoID()
   361  		testSet = append(testSet, id)
   362  		l := rand.Intn(12) + 12
   363  		testKeys = append(testKeys, id[:l])
   364  	}
   365  	b.ResetTimer()
   366  	for i := 0; i < b.N; i++ {
   367  		index := NewTruncIndex([]string{})
   368  		for _, id := range testSet {
   369  			if err := index.Add(id); err != nil {
   370  				b.Fatal(err)
   371  			}
   372  		}
   373  		for _, id := range testKeys {
   374  			if res, err := index.Get(id); err != nil {
   375  				b.Fatal(res, err)
   376  			}
   377  		}
   378  	}
   379  }
   380  
   381  func BenchmarkTruncIndexAddGet250(b *testing.B) {
   382  	var testSet []string
   383  	var testKeys []string
   384  	for i := 0; i < 500; i++ {
   385  		id := stringid.GenerateNonCryptoID()
   386  		testSet = append(testSet, id)
   387  		l := rand.Intn(12) + 12
   388  		testKeys = append(testKeys, id[:l])
   389  	}
   390  	b.ResetTimer()
   391  	for i := 0; i < b.N; i++ {
   392  		index := NewTruncIndex([]string{})
   393  		for _, id := range testSet {
   394  			if err := index.Add(id); err != nil {
   395  				b.Fatal(err)
   396  			}
   397  		}
   398  		for _, id := range testKeys {
   399  			if res, err := index.Get(id); err != nil {
   400  				b.Fatal(res, err)
   401  			}
   402  		}
   403  	}
   404  }
   405  
   406  func BenchmarkTruncIndexAddGet500(b *testing.B) {
   407  	var testSet []string
   408  	var testKeys []string
   409  	for i := 0; i < 500; i++ {
   410  		id := stringid.GenerateNonCryptoID()
   411  		testSet = append(testSet, id)
   412  		l := rand.Intn(12) + 12
   413  		testKeys = append(testKeys, id[:l])
   414  	}
   415  	b.ResetTimer()
   416  	for i := 0; i < b.N; i++ {
   417  		index := NewTruncIndex([]string{})
   418  		for _, id := range testSet {
   419  			if err := index.Add(id); err != nil {
   420  				b.Fatal(err)
   421  			}
   422  		}
   423  		for _, id := range testKeys {
   424  			if res, err := index.Get(id); err != nil {
   425  				b.Fatal(res, err)
   426  			}
   427  		}
   428  	}
   429  }