summaryrefslogtreecommitdiff
path: root/container/view_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'container/view_test.go')
-rw-r--r--container/view_test.go299
1 files changed, 299 insertions, 0 deletions
diff --git a/container/view_test.go b/container/view_test.go
index 290282c907..099da49df9 100644
--- a/container/view_test.go
+++ b/container/view_test.go
@@ -1,12 +1,14 @@
package container // import "github.com/docker/docker/container"
import (
+ "math/rand"
"os"
"path/filepath"
"testing"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/pkg/stringid"
"github.com/google/uuid"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -183,3 +185,300 @@ func TestViewWithHealthCheck(t *testing.T) {
t.Fatalf("expected Health=starting. Got: %+v", s)
}
}
+
+func TestTruncIndex(t *testing.T) {
+ db, err := NewViewDB()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Get on an empty index
+ if _, err := db.GetByPrefix("foobar"); err == nil {
+ t.Fatal("Get on an empty index should return an error")
+ }
+
+ id := "99b36c2c326ccc11e726eee6ee78a0baf166ef96"
+ // Add an id
+ if err := db.Save(&Container{ID: id}); err != nil {
+ t.Fatal(err)
+ }
+
+ type testacase struct {
+ name string
+ input string
+ expectedResult string
+ expectError bool
+ }
+
+ for _, tc := range []testacase{
+ {
+ name: "Get a non-existing id",
+ input: "abracadabra",
+ expectError: true,
+ },
+ {
+ name: "Get an empty id",
+ input: "",
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "Get the exact id",
+ input: id,
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "The first letter should match",
+ input: id[:1],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "The first half should match",
+ input: id[:len(id)/2],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "The second half should NOT match",
+ input: id[len(id)/2:],
+ expectError: true,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ assertIndexGet(t, db, tc.input, tc.expectedResult, tc.expectError)
+ })
+ }
+
+ id2 := id[:6] + "blabla"
+ // Add an id
+ if err := db.Save(&Container{ID: id2}); err != nil {
+ t.Fatal(err)
+ }
+
+ for _, tc := range []testacase{
+ {
+ name: "id should work",
+ input: id,
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "id2 should work",
+ input: id2,
+ expectedResult: id2,
+ expectError: false,
+ },
+ {
+ name: "6 characters should conflict",
+ input: id[:6],
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "4 characters should conflict",
+ input: id[:4],
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "1 character should conflict",
+ input: id[:6],
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "7 characters of id should not conflict",
+ input: id[:7],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "7 characters of id2 should not conflict",
+ input: id2[:7],
+ expectedResult: id2,
+ expectError: false,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ assertIndexGet(t, db, tc.input, tc.expectedResult, tc.expectError)
+ })
+ }
+
+ // Deleting id2 should remove conflicts
+ if err := db.Delete(&Container{ID: id2}); err != nil {
+ t.Fatal(err)
+ }
+
+ for _, tc := range []testacase{
+ {
+ name: "id2 should no longer work",
+ input: id2,
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "7 characters id2 should no longer work",
+ input: id2[:7],
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "11 characters id2 should no longer work",
+ input: id2[:11],
+ expectedResult: "",
+ expectError: true,
+ },
+ {
+ name: "conflicts between id[:6] and id2 should be gone",
+ input: id[:6],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "conflicts between id[:4] and id2 should be gone",
+ input: id[:4],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "conflicts between id[:1] and id2 should be gone",
+ input: id[:1],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "non-conflicting 7 character substrings should still not conflict",
+ input: id[:7],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "non-conflicting 15 character substrings should still not conflict",
+ input: id[:15],
+ expectedResult: id,
+ expectError: false,
+ },
+ {
+ name: "non-conflicting substrings should still not conflict",
+ input: id,
+ expectedResult: id,
+ expectError: false,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ assertIndexGet(t, db, tc.input, tc.expectedResult, tc.expectError)
+ })
+ }
+}
+
+func assertIndexGet(t *testing.T, snapshot ViewDB, input, expectedResult string, expectError bool) {
+ if result, err := snapshot.GetByPrefix(input); err != nil && !expectError {
+ t.Fatalf("Unexpected error getting '%s': %s", input, err)
+ } else if err == nil && expectError {
+ t.Fatalf("Getting '%s' should return an error, not '%s'", input, result)
+ } else if result != expectedResult {
+ t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
+ }
+}
+
+func BenchmarkDBAdd100(b *testing.B) {
+ var testSet []string
+ for i := 0; i < 100; i++ {
+ testSet = append(testSet, stringid.GenerateRandomID())
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ db, err := NewViewDB()
+ if err != nil {
+ b.Fatal(err)
+ }
+ for _, id := range testSet {
+ if err := db.Save(&Container{ID: id}); err != nil {
+ b.Fatal(err)
+ }
+ }
+ }
+}
+
+func BenchmarkDBGetByPrefix100(b *testing.B) {
+ var testSet []string
+ var testKeys []string
+ for i := 0; i < 100; i++ {
+ testSet = append(testSet, stringid.GenerateRandomID())
+ }
+ db, err := NewViewDB()
+ if err != nil {
+ b.Fatal(err)
+ }
+ for _, id := range testSet {
+ if err := db.Save(&Container{ID: 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 := db.GetByPrefix(id); err != nil {
+ b.Fatal(res, err)
+ }
+ }
+ }
+}
+
+func BenchmarkDBGetByPrefix250(b *testing.B) {
+ var testSet []string
+ var testKeys []string
+ for i := 0; i < 250; i++ {
+ testSet = append(testSet, stringid.GenerateRandomID())
+ }
+ db, err := NewViewDB()
+ if err != nil {
+ b.Fatal(err)
+ }
+ for _, id := range testSet {
+ if err := db.Save(&Container{ID: 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 := db.GetByPrefix(id); err != nil {
+ b.Fatal(res, err)
+ }
+ }
+ }
+}
+
+func BenchmarkDBGetByPrefix500(b *testing.B) {
+ var testSet []string
+ var testKeys []string
+ for i := 0; i < 500; i++ {
+ testSet = append(testSet, stringid.GenerateRandomID())
+ }
+ db, err := NewViewDB()
+ if err != nil {
+ b.Fatal(err)
+ }
+ for _, id := range testSet {
+ if err := db.Save(&Container{ID: 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 := db.GetByPrefix(id); err != nil {
+ b.Fatal(res, err)
+ }
+ }
+ }
+}