372 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			372 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Go
		
	
	
| package digestset
 | |
| 
 | |
| import (
 | |
| 	"crypto/sha256"
 | |
| 	_ "crypto/sha512"
 | |
| 	"encoding/binary"
 | |
| 	"math/rand"
 | |
| 	"testing"
 | |
| 
 | |
| 	digest "github.com/opencontainers/go-digest"
 | |
| )
 | |
| 
 | |
| func assertEqualDigests(t *testing.T, d1, d2 digest.Digest) {
 | |
| 	if d1 != d2 {
 | |
| 		t.Fatalf("Digests do not match:\n\tActual: %s\n\tExpected: %s", d1, d2)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestLookup(t *testing.T) {
 | |
| 	digests := []digest.Digest{
 | |
| 		"sha256:1234511111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:1234111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:1234611111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:5432111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6543111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6432111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6542111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6532111111111111111111111111111111111111111111111111111111111111",
 | |
| 	}
 | |
| 
 | |
| 	dset := NewSet()
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	dgst, err := dset.Lookup("54")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	assertEqualDigests(t, dgst, digests[3])
 | |
| 
 | |
| 	_, err = dset.Lookup("1234")
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Expected ambiguous error looking up: 1234")
 | |
| 	}
 | |
| 	if err != ErrDigestAmbiguous {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	_, err = dset.Lookup("9876")
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Expected not found error looking up: 9876")
 | |
| 	}
 | |
| 	if err != ErrDigestNotFound {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	_, err = dset.Lookup("sha256:1234")
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Expected ambiguous error looking up: sha256:1234")
 | |
| 	}
 | |
| 	if err != ErrDigestAmbiguous {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	dgst, err = dset.Lookup("sha256:12345")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	assertEqualDigests(t, dgst, digests[0])
 | |
| 
 | |
| 	dgst, err = dset.Lookup("sha256:12346")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	assertEqualDigests(t, dgst, digests[2])
 | |
| 
 | |
| 	dgst, err = dset.Lookup("12346")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	assertEqualDigests(t, dgst, digests[2])
 | |
| 
 | |
| 	dgst, err = dset.Lookup("12345")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	assertEqualDigests(t, dgst, digests[0])
 | |
| }
 | |
| 
 | |
| func TestAddDuplication(t *testing.T) {
 | |
| 	digests := []digest.Digest{
 | |
| 		"sha256:1234111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:1234511111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:1234611111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:5432111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6543111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha512:65431111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha512:65421111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha512:65321111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
 | |
| 	}
 | |
| 
 | |
| 	dset := NewSet()
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(dset.entries) != 8 {
 | |
| 		t.Fatal("Invalid dset size")
 | |
| 	}
 | |
| 
 | |
| 	if err := dset.Add(digest.Digest("sha256:1234511111111111111111111111111111111111111111111111111111111111")); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if len(dset.entries) != 8 {
 | |
| 		t.Fatal("Duplicate digest insert should not increase entries size")
 | |
| 	}
 | |
| 
 | |
| 	if err := dset.Add(digest.Digest("sha384:123451111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if len(dset.entries) != 9 {
 | |
| 		t.Fatal("Insert with different algorithm should be allowed")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRemove(t *testing.T) {
 | |
| 	digests, err := createDigests(10)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	dset := NewSet()
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	dgst, err := dset.Lookup(digests[0].String())
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if dgst != digests[0] {
 | |
| 		t.Fatalf("Unexpected digest value:\n\tExpected: %s\n\tActual: %s", digests[0], dgst)
 | |
| 	}
 | |
| 
 | |
| 	if err := dset.Remove(digests[0]); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if _, err := dset.Lookup(digests[0].String()); err != ErrDigestNotFound {
 | |
| 		t.Fatalf("Expected error %v when looking up removed digest, got %v", ErrDigestNotFound, err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestAll(t *testing.T) {
 | |
| 	digests, err := createDigests(100)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	dset := NewSet()
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	all := map[digest.Digest]struct{}{}
 | |
| 	for _, dgst := range dset.All() {
 | |
| 		all[dgst] = struct{}{}
 | |
| 	}
 | |
| 
 | |
| 	if len(all) != len(digests) {
 | |
| 		t.Fatalf("Unexpected number of unique digests found:\n\tExpected: %d\n\tActual: %d", len(digests), len(all))
 | |
| 	}
 | |
| 
 | |
| 	for i, dgst := range digests {
 | |
| 		if _, ok := all[dgst]; !ok {
 | |
| 			t.Fatalf("Missing element at position %d: %s", i, dgst)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func assertEqualShort(t *testing.T, actual, expected string) {
 | |
| 	if actual != expected {
 | |
| 		t.Fatalf("Unexpected short value:\n\tExpected: %s\n\tActual: %s", expected, actual)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestShortCodeTable(t *testing.T) {
 | |
| 	digests := []digest.Digest{
 | |
| 		"sha256:1234111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:1234511111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:1234611111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:5432111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6543111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6432111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6542111111111111111111111111111111111111111111111111111111111111",
 | |
| 		"sha256:6532111111111111111111111111111111111111111111111111111111111111",
 | |
| 	}
 | |
| 
 | |
| 	dset := NewSet()
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	dump := ShortCodeTable(dset, 2)
 | |
| 
 | |
| 	if len(dump) < len(digests) {
 | |
| 		t.Fatalf("Error unexpected size: %d, expecting %d", len(dump), len(digests))
 | |
| 	}
 | |
| 	assertEqualShort(t, dump[digests[0]], "12341")
 | |
| 	assertEqualShort(t, dump[digests[1]], "12345")
 | |
| 	assertEqualShort(t, dump[digests[2]], "12346")
 | |
| 	assertEqualShort(t, dump[digests[3]], "54")
 | |
| 	assertEqualShort(t, dump[digests[4]], "6543")
 | |
| 	assertEqualShort(t, dump[digests[5]], "64")
 | |
| 	assertEqualShort(t, dump[digests[6]], "6542")
 | |
| 	assertEqualShort(t, dump[digests[7]], "653")
 | |
| }
 | |
| 
 | |
| func createDigests(count int) ([]digest.Digest, error) {
 | |
| 	r := rand.New(rand.NewSource(25823))
 | |
| 	digests := make([]digest.Digest, count)
 | |
| 	for i := range digests {
 | |
| 		h := sha256.New()
 | |
| 		if err := binary.Write(h, binary.BigEndian, r.Int63()); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		digests[i] = digest.NewDigest("sha256", h)
 | |
| 	}
 | |
| 	return digests, nil
 | |
| }
 | |
| 
 | |
| func benchAddNTable(b *testing.B, n int) {
 | |
| 	digests, err := createDigests(n)
 | |
| 	if err != nil {
 | |
| 		b.Fatal(err)
 | |
| 	}
 | |
| 	b.ResetTimer()
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		dset := &Set{entries: digestEntries(make([]*digestEntry, 0, n))}
 | |
| 		for j := range digests {
 | |
| 			if err = dset.Add(digests[j]); err != nil {
 | |
| 				b.Fatal(err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func benchLookupNTable(b *testing.B, n int, shortLen int) {
 | |
| 	digests, err := createDigests(n)
 | |
| 	if err != nil {
 | |
| 		b.Fatal(err)
 | |
| 	}
 | |
| 	dset := &Set{entries: digestEntries(make([]*digestEntry, 0, n))}
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			b.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 	shorts := make([]string, 0, n)
 | |
| 	for _, short := range ShortCodeTable(dset, shortLen) {
 | |
| 		shorts = append(shorts, short)
 | |
| 	}
 | |
| 
 | |
| 	b.ResetTimer()
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		if _, err = dset.Lookup(shorts[i%n]); err != nil {
 | |
| 			b.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func benchRemoveNTable(b *testing.B, n int) {
 | |
| 	digests, err := createDigests(n)
 | |
| 	if err != nil {
 | |
| 		b.Fatal(err)
 | |
| 	}
 | |
| 	b.ResetTimer()
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		dset := &Set{entries: digestEntries(make([]*digestEntry, 0, n))}
 | |
| 		b.StopTimer()
 | |
| 		for j := range digests {
 | |
| 			if err = dset.Add(digests[j]); err != nil {
 | |
| 				b.Fatal(err)
 | |
| 			}
 | |
| 		}
 | |
| 		b.StartTimer()
 | |
| 		for j := range digests {
 | |
| 			if err = dset.Remove(digests[j]); err != nil {
 | |
| 				b.Fatal(err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func benchShortCodeNTable(b *testing.B, n int, shortLen int) {
 | |
| 	digests, err := createDigests(n)
 | |
| 	if err != nil {
 | |
| 		b.Fatal(err)
 | |
| 	}
 | |
| 	dset := &Set{entries: digestEntries(make([]*digestEntry, 0, n))}
 | |
| 	for i := range digests {
 | |
| 		if err := dset.Add(digests[i]); err != nil {
 | |
| 			b.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	b.ResetTimer()
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		ShortCodeTable(dset, shortLen)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkAdd10(b *testing.B) {
 | |
| 	benchAddNTable(b, 10)
 | |
| }
 | |
| 
 | |
| func BenchmarkAdd100(b *testing.B) {
 | |
| 	benchAddNTable(b, 100)
 | |
| }
 | |
| 
 | |
| func BenchmarkAdd1000(b *testing.B) {
 | |
| 	benchAddNTable(b, 1000)
 | |
| }
 | |
| 
 | |
| func BenchmarkRemove10(b *testing.B) {
 | |
| 	benchRemoveNTable(b, 10)
 | |
| }
 | |
| 
 | |
| func BenchmarkRemove100(b *testing.B) {
 | |
| 	benchRemoveNTable(b, 100)
 | |
| }
 | |
| 
 | |
| func BenchmarkRemove1000(b *testing.B) {
 | |
| 	benchRemoveNTable(b, 1000)
 | |
| }
 | |
| 
 | |
| func BenchmarkLookup10(b *testing.B) {
 | |
| 	benchLookupNTable(b, 10, 12)
 | |
| }
 | |
| 
 | |
| func BenchmarkLookup100(b *testing.B) {
 | |
| 	benchLookupNTable(b, 100, 12)
 | |
| }
 | |
| 
 | |
| func BenchmarkLookup1000(b *testing.B) {
 | |
| 	benchLookupNTable(b, 1000, 12)
 | |
| }
 | |
| 
 | |
| func BenchmarkShortCode10(b *testing.B) {
 | |
| 	benchShortCodeNTable(b, 10, 12)
 | |
| }
 | |
| func BenchmarkShortCode100(b *testing.B) {
 | |
| 	benchShortCodeNTable(b, 100, 12)
 | |
| }
 | |
| func BenchmarkShortCode1000(b *testing.B) {
 | |
| 	benchShortCodeNTable(b, 1000, 12)
 | |
| }
 |