istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/ledger/ledger_test.go (about) 1 // Copyright 2019 Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ledger 16 17 import ( 18 "fmt" 19 "math/rand" 20 "strconv" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/google/uuid" 26 "github.com/spaolacci/murmur3" 27 "golang.org/x/sync/errgroup" 28 29 "istio.io/istio/pkg/test/util/assert" 30 ) 31 32 func TestLongKeys(t *testing.T) { 33 longKey := "virtual-service/frontend/default" 34 l := smtLedger{tree: newSMT(hasher, nil, time.Minute)} 35 _, err := l.Put(longKey+"1", "1") 36 assert.NoError(t, err) 37 _, err = l.Put(longKey+"2", "2") 38 assert.NoError(t, err) 39 res, err := l.Get(longKey + "1") 40 assert.NoError(t, err) 41 assert.Equal(t, res, "1") 42 res, err = l.Get(longKey + "2") 43 assert.NoError(t, err) 44 assert.Equal(t, res, "2") 45 res, err = l.Get(longKey) 46 assert.NoError(t, err) 47 assert.Equal(t, res, "") 48 } 49 50 func TestGetAndPrevious(t *testing.T) { 51 l := smtLedger{tree: newSMT(hasher, nil, time.Minute)} 52 resultHashes := map[string]bool{} 53 l.Put("foo", "bar") 54 firstHash := l.RootHash() 55 56 resultHashes[l.RootHash()] = true 57 l.Put("foo", "baz") 58 resultHashes[l.RootHash()] = true 59 l.Put("second", "value") 60 resultHashes[l.RootHash()] = true 61 getResult, err := l.Get("foo") 62 assert.NoError(t, err) 63 assert.Equal(t, getResult, "baz") 64 getResult, err = l.Get("second") 65 assert.NoError(t, err) 66 assert.Equal(t, getResult, "value") 67 getResult, err = l.GetPreviousValue(firstHash, "foo") 68 assert.NoError(t, err) 69 assert.Equal(t, getResult, "bar") 70 if len(resultHashes) != 3 { 71 t.Fatal("Encountered has collision") 72 } 73 } 74 75 func TestOrderAgnosticism(t *testing.T) { 76 l := smtLedger{tree: newSMT(MyHasher, nil, time.Minute)} 77 _, err := l.Put("foo", "bar") 78 assert.NoError(t, err) 79 firstHash, err := l.Put("second", "value") 80 assert.NoError(t, err) 81 secondHash, err := l.Put("foo", "baz") 82 assert.NoError(t, err) 83 assert.Equal(t, firstHash != secondHash, true) 84 lastHash, err := l.Put("foo", "bar") 85 assert.NoError(t, err) 86 assert.Equal(t, firstHash, lastHash) 87 } 88 89 func MyHasher(data ...[]byte) (result []byte) { 90 hasher := murmur3.New64() 91 for i := 0; i < len(data); i++ { 92 hasher.Write(data[i]) 93 } 94 result = hasher.Sum(nil) 95 hasher.Reset() 96 return 97 } 98 99 func TestCollision(t *testing.T) { 100 hit := false 101 HashCollider := func(data ...[]byte) []byte { 102 if hit { 103 return []byte{ 104 0xde, 105 0xad, 106 0xbe, 107 0xef, 108 0xde, 109 0xad, 110 0xbe, 111 0xef, 112 } 113 } 114 return MyHasher(data...) 115 } 116 l := smtLedger{tree: newSMT(HashCollider, nil, time.Minute)} 117 hit = true 118 _, err := l.Put("foo", "bar") 119 assert.NoError(t, err) 120 _, err = l.Put("fhgwgads", "shouldcollide") 121 assert.NoError(t, err) 122 value, err := l.Get("foo") 123 assert.NoError(t, err) 124 assert.Equal(t, value, "bar") 125 } 126 127 func HashCollider(data ...[]byte) []byte { 128 return MyHasher(data...) 129 } 130 131 // nolint: gosec 132 // test only code 133 func BenchmarkScale(b *testing.B) { 134 const configSize = 100 135 b.ReportAllocs() 136 b.SetBytes(8) 137 l := &smtLedger{tree: newSMT(HashCollider, nil, time.Minute)} 138 var eg errgroup.Group 139 ids := make([]string, 0, configSize) 140 for i := 0; i < configSize; i++ { 141 ids = append(ids, addConfig(l, b)) 142 } 143 b.ResetTimer() 144 for n := 0; n < b.N; n++ { 145 eg.Go(func() error { 146 _, err := l.Put(ids[rand.Int()%configSize], strconv.Itoa(rand.Int())) 147 _ = l.RootHash() 148 return err 149 }) 150 } 151 if err := eg.Wait(); err != nil { 152 b.Fatalf("An error occurred putting new data on the ledger: %v", err) 153 } 154 b.StopTimer() 155 } 156 157 // nolint: gosec 158 // test only code 159 func addConfig(ledger Ledger, b *testing.B) string { 160 objectID := strings.Replace(uuid.New().String(), "-", "", -1) 161 _, err := ledger.Put(objectID, fmt.Sprintf("%d", rand.Int())) 162 assert.NoError(b, err) 163 return objectID 164 }