github.com/zhyoulun/cilium@v1.6.12/pkg/kvstore/store/store_test.go (about) 1 // Copyright 2018-2019 Authors of Cilium 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 // +build !privileged_tests 16 17 package store 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "testing" 23 "time" 24 25 "github.com/cilium/cilium/pkg/defaults" 26 "github.com/cilium/cilium/pkg/kvstore" 27 "github.com/cilium/cilium/pkg/lock" 28 "github.com/cilium/cilium/pkg/option" 29 "github.com/cilium/cilium/pkg/testutils" 30 31 . "gopkg.in/check.v1" 32 ) 33 34 const ( 35 testPrefix = "store-tests" 36 ) 37 38 func Test(t *testing.T) { 39 TestingT(t) 40 } 41 42 type StoreSuite struct{} 43 44 type StoreEtcdSuite struct { 45 StoreSuite 46 } 47 48 var _ = Suite(&StoreEtcdSuite{}) 49 50 func (e *StoreEtcdSuite) SetUpTest(c *C) { 51 kvstore.SetupDummy("etcd") 52 } 53 54 func (e *StoreEtcdSuite) TearDownTest(c *C) { 55 kvstore.Client().DeletePrefix(testPrefix) 56 kvstore.Client().Close() 57 } 58 59 type StoreConsulSuite struct { 60 StoreSuite 61 } 62 63 var _ = Suite(&StoreConsulSuite{}) 64 65 func (e *StoreConsulSuite) SetUpTest(c *C) { 66 kvstore.SetupDummy("consul") 67 } 68 69 func (e *StoreConsulSuite) TearDownTest(c *C) { 70 kvstore.Client().DeletePrefix(testPrefix) 71 kvstore.Client().Close() 72 time.Sleep(defaults.NodeDeleteDelay + 5*time.Second) 73 } 74 75 type TestType struct { 76 Name string 77 } 78 79 var _ = TestType{} 80 81 func (t *TestType) GetKeyName() string { return t.Name } 82 func (t *TestType) DeepKeyCopy() LocalKey { return &TestType{Name: t.Name} } 83 func (t *TestType) Marshal() ([]byte, error) { return json.Marshal(t) } 84 func (t *TestType) Unmarshal(data []byte) error { return json.Unmarshal(data, t) } 85 86 type opCounter struct { 87 deleted int 88 updated int 89 } 90 91 var ( 92 counter = map[string]*opCounter{} 93 counterLock lock.RWMutex 94 ) 95 96 func (t *TestType) deleted() int { 97 counterLock.RLock() 98 defer counterLock.RUnlock() 99 return counter[t.Name].deleted 100 } 101 102 func (t *TestType) updated() int { 103 counterLock.RLock() 104 defer counterLock.RUnlock() 105 return counter[t.Name].updated 106 } 107 108 func initTestType(name string) TestType { 109 t := TestType{} 110 t.Name = name 111 counterLock.Lock() 112 counter[name] = &opCounter{} 113 counterLock.Unlock() 114 return t 115 } 116 117 type observer struct{} 118 119 func (o *observer) OnUpdate(k Key) { 120 counterLock.Lock() 121 if c, ok := counter[k.(*TestType).Name]; ok { 122 c.updated++ 123 } 124 counterLock.Unlock() 125 } 126 func (o *observer) OnDelete(k NamedKey) { 127 counterLock.Lock() 128 counter[k.(*TestType).Name].deleted++ 129 counterLock.Unlock() 130 } 131 132 func newTestType() Key { 133 t := TestType{} 134 return &t 135 } 136 137 func (s *StoreSuite) TestStoreCreation(c *C) { 138 // Missing Prefix must result in error 139 store, err := JoinSharedStore(Configuration{}) 140 c.Assert(err, ErrorMatches, "prefix must be specified") 141 c.Assert(store, IsNil) 142 143 // Missing KeyCreator must result in error 144 store, err = JoinSharedStore(Configuration{Prefix: testutils.RandomRune()}) 145 c.Assert(err, ErrorMatches, "KeyCreator must be specified") 146 c.Assert(store, IsNil) 147 148 // Basic creation should result in default values 149 store, err = JoinSharedStore(Configuration{Prefix: testutils.RandomRune(), KeyCreator: newTestType}) 150 c.Assert(err, IsNil) 151 c.Assert(store, Not(IsNil)) 152 c.Assert(store.conf.SynchronizationInterval, Equals, option.Config.KVstorePeriodicSync) 153 store.Close() 154 155 // Test with kvstore client specified 156 store, err = JoinSharedStore(Configuration{Prefix: testutils.RandomRune(), KeyCreator: newTestType, Backend: kvstore.Client()}) 157 c.Assert(err, IsNil) 158 c.Assert(store, Not(IsNil)) 159 c.Assert(store.conf.SynchronizationInterval, Equals, option.Config.KVstorePeriodicSync) 160 store.Close() 161 } 162 163 func expect(check func() bool) error { 164 start := time.Now() 165 for { 166 if check() { 167 return nil 168 } 169 170 if time.Since(start) > defaults.NodeDeleteDelay+10*time.Second { 171 return fmt.Errorf("timeout while waiting for expected value") 172 } 173 174 time.Sleep(10 * time.Millisecond) 175 } 176 } 177 178 func (s *StoreSuite) TestStoreOperations(c *C) { 179 // Basic creation should result in default values 180 store, err := JoinSharedStore(Configuration{Prefix: testutils.RandomRune(), KeyCreator: newTestType, Observer: &observer{}}) 181 c.Assert(err, IsNil) 182 c.Assert(store, Not(IsNil)) 183 defer store.Close() 184 185 localKey1 := initTestType("local1") 186 localKey2 := initTestType("local2") 187 localKey3 := initTestType("local3") 188 189 err = store.UpdateLocalKeySync(&localKey1) 190 c.Assert(err, IsNil) 191 err = store.UpdateLocalKeySync(&localKey2) 192 c.Assert(err, IsNil) 193 194 // due to the short sync interval, it is possible that multiple updates 195 // have occurred, make the test reliable by succeeding on at lest one 196 // update 197 c.Assert(expect(func() bool { return localKey1.updated() >= 1 }), IsNil) 198 c.Assert(expect(func() bool { return localKey2.updated() >= 1 }), IsNil) 199 c.Assert(expect(func() bool { return localKey3.updated() == 0 }), IsNil) 200 201 store.DeleteLocalKey(&localKey1) 202 // localKey1 will be deleted 2 times, one from local key and other from 203 // the kvstore watcher 204 c.Assert(expect(func() bool { return localKey1.deleted() == 2 }), IsNil) 205 c.Assert(expect(func() bool { return localKey2.deleted() == 0 }), IsNil) 206 c.Assert(expect(func() bool { return localKey3.deleted() == 0 }), IsNil) 207 208 store.DeleteLocalKey(&localKey3) 209 // localKey3 won't be deleted because it was never added 210 c.Assert(expect(func() bool { return localKey3.deleted() == 0 }), IsNil) 211 212 store.DeleteLocalKey(&localKey2) 213 c.Assert(expect(func() bool { return localKey1.deleted() == 2 }), IsNil) 214 // localKey2 will be deleted 2 times, one from local key and other from 215 // the kvstore watcher 216 c.Assert(expect(func() bool { return localKey2.deleted() == 2 }), IsNil) 217 c.Assert(expect(func() bool { return localKey3.deleted() == 0 }), IsNil) 218 } 219 220 func (s *StoreSuite) TestStorePeriodicSync(c *C) { 221 // Create a store with a very short periodic sync interval 222 store, err := JoinSharedStore(Configuration{ 223 Prefix: testutils.RandomRune(), 224 KeyCreator: newTestType, 225 SynchronizationInterval: 10 * time.Millisecond, 226 Observer: &observer{}, 227 }) 228 c.Assert(err, IsNil) 229 c.Assert(store, Not(IsNil)) 230 defer store.Close() 231 232 localKey1 := initTestType("local1") 233 localKey2 := initTestType("local2") 234 235 err = store.UpdateLocalKeySync(&localKey1) 236 c.Assert(err, IsNil) 237 err = store.UpdateLocalKeySync(&localKey2) 238 c.Assert(err, IsNil) 239 240 c.Assert(expect(func() bool { return localKey1.updated() >= 1 }), IsNil) 241 c.Assert(expect(func() bool { return localKey2.updated() >= 1 }), IsNil) 242 243 store.DeleteLocalKey(&localKey1) 244 store.DeleteLocalKey(&localKey2) 245 246 c.Assert(expect(func() bool { return localKey1.deleted() == 1 }), IsNil) 247 c.Assert(expect(func() bool { return localKey2.deleted() == 1 }), IsNil) 248 } 249 250 func (s *StoreSuite) TestStoreLocalKeyProtection(c *C) { 251 store, err := JoinSharedStore(Configuration{ 252 Prefix: testutils.RandomRune(), 253 KeyCreator: newTestType, 254 SynchronizationInterval: time.Hour, // ensure that periodic sync does not interfer 255 Observer: &observer{}, 256 }) 257 c.Assert(err, IsNil) 258 c.Assert(store, Not(IsNil)) 259 defer store.Close() 260 261 localKey1 := initTestType("local1") 262 263 err = store.UpdateLocalKeySync(&localKey1) 264 c.Assert(err, IsNil) 265 266 c.Assert(expect(func() bool { return localKey1.updated() >= 1 }), IsNil) 267 // delete all keys 268 kvstore.Client().DeletePrefix(store.conf.Prefix) 269 c.Assert(expect(func() bool { 270 v, err := kvstore.Client().Get(store.keyPath(&localKey1)) 271 return err == nil && string(v) != "" 272 }), IsNil) 273 } 274 275 func setupStoreCollaboration(c *C, storePrefix, keyPrefix string) *SharedStore { 276 store, err := JoinSharedStore(Configuration{ 277 Prefix: storePrefix, 278 KeyCreator: newTestType, 279 SynchronizationInterval: time.Second, 280 Observer: &observer{}, 281 }) 282 c.Assert(err, IsNil) 283 c.Assert(store, Not(IsNil)) 284 285 localKey1 := initTestType(keyPrefix + "-local1") 286 err = store.UpdateLocalKeySync(&localKey1) 287 c.Assert(err, IsNil) 288 289 localKey2 := initTestType(keyPrefix + "-local2") 290 err = store.UpdateLocalKeySync(&localKey2) 291 c.Assert(err, IsNil) 292 293 // wait until local keys was inserted and until the kvstore has confirmed the 294 c.Assert(expect(func() bool { return localKey1.updated() >= 1 }), IsNil) 295 c.Assert(expect(func() bool { return localKey2.updated() >= 1 }), IsNil) 296 297 c.Assert(len(store.getLocalKeys()), Equals, 2) 298 299 return store 300 } 301 302 func (s *StoreSuite) TestStoreCollaboration(c *C) { 303 storePrefix := testutils.RandomRune() 304 305 collab1 := setupStoreCollaboration(c, storePrefix, testutils.RandomRune()) 306 defer collab1.Close() 307 308 collab2 := setupStoreCollaboration(c, storePrefix, testutils.RandomRune()) 309 defer collab2.Close() 310 311 c.Assert(expect(func() bool { 312 totalKeys := len(collab1.getLocalKeys()) + len(collab2.getLocalKeys()) 313 keys1, keys2 := collab1.getSharedKeys(), collab2.getSharedKeys() 314 315 log.Debugf("totalKeys %d == keys1 %d == keys2 %d", totalKeys, len(keys1), len(keys2)) 316 return len(keys1) == totalKeys && len(keys1) == len(keys2) 317 }), IsNil) 318 }