2018-02-05 16:05:59 -05:00
|
|
|
package truncindex // import "github.com/docker/docker/pkg/truncindex"
|
2014-06-24 13:19:15 -04:00
|
|
|
|
2014-06-24 13:41:51 -04:00
|
|
|
import (
|
|
|
|
"math/rand"
|
|
|
|
"testing"
|
2017-01-06 09:14:10 -05:00
|
|
|
"time"
|
2014-06-24 13:41:51 -04:00
|
|
|
|
2015-03-24 07:25:26 -04:00
|
|
|
"github.com/docker/docker/pkg/stringid"
|
2014-06-24 13:41:51 -04:00
|
|
|
)
|
2014-06-24 13:19:15 -04:00
|
|
|
|
|
|
|
// Test the behavior of TruncIndex, an index for querying IDs from a non-conflicting prefix.
|
|
|
|
func TestTruncIndex(t *testing.T) {
|
|
|
|
ids := []string{}
|
|
|
|
index := NewTruncIndex(ids)
|
|
|
|
// Get on an empty index
|
|
|
|
if _, err := index.Get("foobar"); err == nil {
|
|
|
|
t.Fatal("Get on an empty index should return an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Spaces should be illegal in an id
|
|
|
|
if err := index.Add("I have a space"); err == nil {
|
|
|
|
t.Fatalf("Adding an id with ' ' should return an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
id := "99b36c2c326ccc11e726eee6ee78a0baf166ef96"
|
|
|
|
// Add an id
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2014-06-24 18:24:02 -04:00
|
|
|
|
|
|
|
// Add an empty id (should fail)
|
|
|
|
if err := index.Add(""); err == nil {
|
|
|
|
t.Fatalf("Adding an empty id should return an error")
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:19:15 -04:00
|
|
|
// Get a non-existing id
|
|
|
|
assertIndexGet(t, index, "abracadabra", "", true)
|
2014-06-24 18:24:02 -04:00
|
|
|
// Get an empty id
|
|
|
|
assertIndexGet(t, index, "", "", true)
|
2014-06-24 13:19:15 -04:00
|
|
|
// Get the exact id
|
|
|
|
assertIndexGet(t, index, id, id, false)
|
|
|
|
// The first letter should match
|
|
|
|
assertIndexGet(t, index, id[:1], id, false)
|
|
|
|
// The first half should match
|
|
|
|
assertIndexGet(t, index, id[:len(id)/2], id, false)
|
|
|
|
// The second half should NOT match
|
|
|
|
assertIndexGet(t, index, id[len(id)/2:], "", true)
|
|
|
|
|
|
|
|
id2 := id[:6] + "blabla"
|
|
|
|
// Add an id
|
|
|
|
if err := index.Add(id2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
// Both exact IDs should work
|
|
|
|
assertIndexGet(t, index, id, id, false)
|
|
|
|
assertIndexGet(t, index, id2, id2, false)
|
|
|
|
|
|
|
|
// 6 characters or less should conflict
|
|
|
|
assertIndexGet(t, index, id[:6], "", true)
|
|
|
|
assertIndexGet(t, index, id[:4], "", true)
|
|
|
|
assertIndexGet(t, index, id[:1], "", true)
|
|
|
|
|
2014-12-16 18:06:35 -05:00
|
|
|
// An ambiguous id prefix should return an error
|
2015-03-26 06:36:13 -04:00
|
|
|
if _, err := index.Get(id[:4]); err == nil {
|
2014-12-16 18:06:35 -05:00
|
|
|
t.Fatal("An ambiguous id prefix should return an error")
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:19:15 -04:00
|
|
|
// 7 characters should NOT conflict
|
|
|
|
assertIndexGet(t, index, id[:7], id, false)
|
|
|
|
assertIndexGet(t, index, id2[:7], id2, false)
|
|
|
|
|
|
|
|
// Deleting a non-existing id should return an error
|
|
|
|
if err := index.Delete("non-existing"); err == nil {
|
|
|
|
t.Fatalf("Deleting a non-existing id should return an error")
|
|
|
|
}
|
|
|
|
|
2014-06-24 18:24:02 -04:00
|
|
|
// Deleting an empty id should return an error
|
|
|
|
if err := index.Delete(""); err == nil {
|
|
|
|
t.Fatal("Deleting an empty id should return an error")
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:19:15 -04:00
|
|
|
// Deleting id2 should remove conflicts
|
|
|
|
if err := index.Delete(id2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
// id2 should no longer work
|
|
|
|
assertIndexGet(t, index, id2, "", true)
|
|
|
|
assertIndexGet(t, index, id2[:7], "", true)
|
|
|
|
assertIndexGet(t, index, id2[:11], "", true)
|
|
|
|
|
|
|
|
// conflicts between id and id2 should be gone
|
|
|
|
assertIndexGet(t, index, id[:6], id, false)
|
|
|
|
assertIndexGet(t, index, id[:4], id, false)
|
|
|
|
assertIndexGet(t, index, id[:1], id, false)
|
|
|
|
|
|
|
|
// non-conflicting substrings should still not conflict
|
|
|
|
assertIndexGet(t, index, id[:7], id, false)
|
|
|
|
assertIndexGet(t, index, id[:15], id, false)
|
|
|
|
assertIndexGet(t, index, id, id, false)
|
2015-06-19 11:01:39 -04:00
|
|
|
|
|
|
|
assertIndexIterate(t)
|
2017-01-06 09:14:10 -05:00
|
|
|
assertIndexIterateDoNotPanic(t)
|
2015-06-19 11:01:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func assertIndexIterate(t *testing.T) {
|
|
|
|
ids := []string{
|
|
|
|
"19b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
|
|
|
"28b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
|
|
|
"37b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
|
|
|
"46b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
|
|
|
}
|
|
|
|
|
|
|
|
index := NewTruncIndex(ids)
|
|
|
|
|
|
|
|
index.Iterate(func(targetId string) {
|
|
|
|
for _, id := range ids {
|
|
|
|
if targetId == id {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Fatalf("An unknown ID '%s'", targetId)
|
|
|
|
})
|
2014-06-24 13:19:15 -04:00
|
|
|
}
|
|
|
|
|
2017-01-06 09:14:10 -05:00
|
|
|
func assertIndexIterateDoNotPanic(t *testing.T) {
|
|
|
|
ids := []string{
|
|
|
|
"19b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
|
|
|
"28b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
|
|
|
}
|
|
|
|
|
|
|
|
index := NewTruncIndex(ids)
|
|
|
|
iterationStarted := make(chan bool, 1)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-iterationStarted
|
|
|
|
index.Delete("19b36c2c326ccc11e726eee6ee78a0baf166ef96")
|
|
|
|
}()
|
|
|
|
|
|
|
|
index.Iterate(func(targetId string) {
|
|
|
|
if targetId == "19b36c2c326ccc11e726eee6ee78a0baf166ef96" {
|
|
|
|
iterationStarted <- true
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:19:15 -04:00
|
|
|
func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {
|
|
|
|
if result, err := index.Get(input); err != nil && !expectError {
|
|
|
|
t.Fatalf("Unexpected error getting '%s': %s", input, err)
|
|
|
|
} else if err == nil && expectError {
|
2014-06-24 18:24:02 -04:00
|
|
|
t.Fatalf("Getting '%s' should return an error, not '%s'", input, result)
|
2014-06-24 13:19:15 -04:00
|
|
|
} else if result != expectedResult {
|
|
|
|
t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:41:51 -04:00
|
|
|
func BenchmarkTruncIndexAdd100(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 100; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
2014-06-24 13:19:15 -04:00
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
index := NewTruncIndex([]string{})
|
2014-06-24 13:41:51 -04:00
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexAdd250(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 250; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexAdd500(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexGet100(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
var testKeys []string
|
|
|
|
for i := 0; i < 100; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
l := rand.Intn(12) + 12
|
|
|
|
testKeys = append(testKeys, id[:l])
|
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
for _, id := range testKeys {
|
|
|
|
if res, err := index.Get(id); err != nil {
|
|
|
|
b.Fatal(res, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexGet250(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
var testKeys []string
|
|
|
|
for i := 0; i < 250; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
l := rand.Intn(12) + 12
|
|
|
|
testKeys = append(testKeys, id[:l])
|
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
for _, id := range testKeys {
|
|
|
|
if res, err := index.Get(id); err != nil {
|
|
|
|
b.Fatal(res, err)
|
|
|
|
}
|
2014-06-24 13:19:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:41:51 -04:00
|
|
|
func BenchmarkTruncIndexGet500(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
var testKeys []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
l := rand.Intn(12) + 12
|
|
|
|
testKeys = append(testKeys, id[:l])
|
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
for _, id := range testKeys {
|
|
|
|
if res, err := index.Get(id); err != nil {
|
|
|
|
b.Fatal(res, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 01:37:39 -04:00
|
|
|
func BenchmarkTruncIndexDelete100(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 100; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-25 01:37:39 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
b.StopTimer()
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b.StartTimer()
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Delete(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexDelete250(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 250; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-25 01:37:39 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
b.StopTimer()
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b.StartTimer()
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Delete(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexDelete500(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-25 01:37:39 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
b.StopTimer()
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b.StartTimer()
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Delete(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:41:51 -04:00
|
|
|
func BenchmarkTruncIndexNew100(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 100; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
NewTruncIndex(testSet)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexNew250(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 250; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
NewTruncIndex(testSet)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexNew500(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
2014-06-24 13:41:51 -04:00
|
|
|
}
|
2014-06-24 13:19:15 -04:00
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
2014-06-24 13:41:51 -04:00
|
|
|
NewTruncIndex(testSet)
|
2014-06-24 13:19:15 -04:00
|
|
|
}
|
|
|
|
}
|
2014-06-25 14:49:38 -04:00
|
|
|
|
|
|
|
func BenchmarkTruncIndexAddGet100(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
var testKeys []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
id := stringid.GenerateNonCryptoID()
|
2014-06-25 14:49:38 -04:00
|
|
|
testSet = append(testSet, id)
|
|
|
|
l := rand.Intn(12) + 12
|
|
|
|
testKeys = append(testKeys, id[:l])
|
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, id := range testKeys {
|
|
|
|
if res, err := index.Get(id); err != nil {
|
|
|
|
b.Fatal(res, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexAddGet250(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
var testKeys []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
id := stringid.GenerateNonCryptoID()
|
2014-06-25 14:49:38 -04:00
|
|
|
testSet = append(testSet, id)
|
|
|
|
l := rand.Intn(12) + 12
|
|
|
|
testKeys = append(testKeys, id[:l])
|
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, id := range testKeys {
|
|
|
|
if res, err := index.Get(id); err != nil {
|
|
|
|
b.Fatal(res, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkTruncIndexAddGet500(b *testing.B) {
|
|
|
|
var testSet []string
|
|
|
|
var testKeys []string
|
|
|
|
for i := 0; i < 500; i++ {
|
2015-07-28 20:19:17 -04:00
|
|
|
id := stringid.GenerateNonCryptoID()
|
2014-06-25 14:49:38 -04:00
|
|
|
testSet = append(testSet, id)
|
|
|
|
l := rand.Intn(12) + 12
|
|
|
|
testKeys = append(testKeys, id[:l])
|
|
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
index := NewTruncIndex([]string{})
|
|
|
|
for _, id := range testSet {
|
|
|
|
if err := index.Add(id); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, id := range testKeys {
|
|
|
|
if res, err := index.Get(id); err != nil {
|
|
|
|
b.Fatal(res, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|