github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/truncindex/truncindex_test.go (about)

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