blob: f96ed19f4fc1832b544da022c166e784e0d0b5d5 [file] [log] [blame]
Girish Kumarca522102019-11-08 11:26:35 +00001/*
2 * Copyright 2019-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package db
18
19import (
20 "context"
serkant.uluderyab38671c2019-11-01 09:35:38 -070021 "os"
22 "testing"
23 "time"
24
khenaidoob6238b32020-04-07 12:07:36 -040025 mocks "github.com/opencord/voltha-lib-go/v3/pkg/mocks/etcd"
khenaidooc7005fc2019-11-18 19:23:57 -050026 "github.com/phayes/freeport"
Girish Kumarca522102019-11-08 11:26:35 +000027 "github.com/stretchr/testify/assert"
28 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
Girish Kumarca522102019-11-08 11:26:35 +000030)
31
Girish Kumarca522102019-11-08 11:26:35 +000032const (
33 embedEtcdServerHost = "localhost"
Neha Sharma130ac6d2020-04-08 08:46:32 +000034 defaultTimeout = 1 * time.Second
Girish Kumarca522102019-11-08 11:26:35 +000035 defaultPathPrefix = "Prefix"
36)
37
khenaidooc7005fc2019-11-18 19:23:57 -050038var (
39 embedEtcdServerPort int
40 dummyEtcdServerPort int
41)
Girish Kumarca522102019-11-08 11:26:35 +000042
khenaidooc7005fc2019-11-18 19:23:57 -050043func TestMain(m *testing.M) {
44 var err error
45 embedEtcdServerPort, err = freeport.GetFreePort()
46 if err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -050047 logger.Fatal(err)
khenaidooc7005fc2019-11-18 19:23:57 -050048 }
49 dummyEtcdServerPort, err = freeport.GetFreePort()
50 if err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -050051 logger.Fatal(err)
khenaidooc7005fc2019-11-18 19:23:57 -050052 }
53 peerPort, err := freeport.GetFreePort()
54 if err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -050055 logger.Fatal(err)
khenaidooc7005fc2019-11-18 19:23:57 -050056 }
57 etcdServer := mocks.StartEtcdServer(mocks.MKConfig("voltha.db.test", embedEtcdServerPort, peerPort, "voltha.lib.db", "error"))
Girish Kumarca522102019-11-08 11:26:35 +000058 res := m.Run()
59
60 etcdServer.Stop()
61 os.Exit(res)
62}
63
64func provisionBackendWithEmbeddedEtcdServer(t *testing.T) *Backend {
65 backend := NewBackend("etcd", embedEtcdServerHost, embedEtcdServerPort, defaultTimeout, defaultPathPrefix)
66 assert.NotNil(t, backend)
67 assert.NotNil(t, backend.Client)
68 return backend
69}
70
71func provisionBackendWithDummyEtcdServer(t *testing.T) *Backend {
72 backend := NewBackend("etcd", embedEtcdServerHost, dummyEtcdServerPort, defaultTimeout, defaultPathPrefix)
73 assert.NotNil(t, backend)
74 assert.NotNil(t, backend.Client)
75 return backend
76}
77
78// Create instance using Etcd Kvstore
79func TestNewBackend_EtcdKvStore(t *testing.T) {
80 backend := NewBackend("etcd", embedEtcdServerHost, embedEtcdServerPort, defaultTimeout, defaultPathPrefix)
81
82 // Verify all attributes of backend have got set correctly
83 assert.NotNil(t, backend)
84 assert.NotNil(t, backend.Client)
85 assert.Equal(t, backend.StoreType, "etcd")
86 assert.Equal(t, backend.Host, embedEtcdServerHost)
87 assert.Equal(t, backend.Port, embedEtcdServerPort)
88 assert.Equal(t, backend.Timeout, defaultTimeout)
89 assert.Equal(t, backend.PathPrefix, defaultPathPrefix)
90 assert.Equal(t, backend.alive, false) // backend is not alive at start
91 assert.Nil(t, backend.liveness) // no liveness channel is created at start
92 assert.Equal(t, backend.LivenessChannelInterval, DefaultLivenessChannelInterval)
93}
94
95// Create instance using Consul Kvstore
96func TestNewBackend_ConsulKvStore(t *testing.T) {
97 backend := NewBackend("consul", embedEtcdServerHost, embedEtcdServerPort, defaultTimeout, defaultPathPrefix)
98
99 // Verify kvstore type attribute of backend has got set correctly
100 assert.NotNil(t, backend)
101 assert.NotNil(t, backend.Client)
102 assert.Equal(t, backend.StoreType, "consul")
103}
104
105// Create instance using Invalid Kvstore; instance creation should fail
106func TestNewBackend_InvalidKvstore(t *testing.T) {
107 backend := NewBackend("unknown", embedEtcdServerHost, embedEtcdServerPort, defaultTimeout, defaultPathPrefix)
108
109 assert.NotNil(t, backend)
110 assert.Nil(t, backend.Client)
111}
112
113func TestMakePath(t *testing.T) {
114 backend := provisionBackendWithEmbeddedEtcdServer(t)
115 path := backend.makePath("Suffix")
116 assert.Equal(t, defaultPathPrefix+"/Suffix", path)
117}
118
119// Liveness Check against Embedded Etcd Server should return alive state
120func TestPerformLivenessCheck_EmbeddedEtcdServer(t *testing.T) {
121 backend := provisionBackendWithEmbeddedEtcdServer(t)
Neha Sharma130ac6d2020-04-08 08:46:32 +0000122 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
npujar5bf737f2020-01-16 19:35:25 +0530123 defer cancel()
124 alive := backend.PerformLivenessCheck(ctx)
Girish Kumarca522102019-11-08 11:26:35 +0000125 assert.True(t, alive)
126}
127
128// Liveness Check against Dummy Etcd Server should return not-alive state
129func TestPerformLivenessCheck_DummyEtcdServer(t *testing.T) {
130 backend := provisionBackendWithDummyEtcdServer(t)
Neha Sharma130ac6d2020-04-08 08:46:32 +0000131 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
npujar5bf737f2020-01-16 19:35:25 +0530132 defer cancel()
133 alive := backend.PerformLivenessCheck(ctx)
Girish Kumarca522102019-11-08 11:26:35 +0000134 assert.False(t, alive)
135}
136
137// Enabling Liveness Channel before First Liveness Check
138func TestEnableLivenessChannel_EmbeddedEtcdServer_BeforeLivenessCheck(t *testing.T) {
139 backend := provisionBackendWithEmbeddedEtcdServer(t)
140
141 alive := backend.EnableLivenessChannel()
142 assert.NotNil(t, alive)
143 assert.Equal(t, 1, len(alive))
144 assert.Equal(t, false, <-alive)
145 assert.NotNil(t, backend.liveness)
146}
147
148// Enabling Liveness Channel after First Liveness Check
149func TestEnableLivenessChannel_EmbeddedEtcdServer_AfterLivenessCheck(t *testing.T) {
150 backend := provisionBackendWithEmbeddedEtcdServer(t)
Neha Sharma130ac6d2020-04-08 08:46:32 +0000151 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
npujar5bf737f2020-01-16 19:35:25 +0530152 defer cancel()
153 backend.PerformLivenessCheck(ctx)
Girish Kumarca522102019-11-08 11:26:35 +0000154
155 alive := backend.EnableLivenessChannel()
156 assert.NotNil(t, alive)
157 assert.Equal(t, 1, len(alive))
158 assert.Equal(t, true, <-alive)
159 assert.NotNil(t, backend.liveness)
160}
161
162// Update Liveness with alive status change
163func TestUpdateLiveness_AliveStatusChange(t *testing.T) {
164 backend := provisionBackendWithEmbeddedEtcdServer(t)
165 // Enable Liveness Channel and verify initial state is not-alive
166 aliveState := backend.EnableLivenessChannel()
167 assert.NotNil(t, aliveState)
168 assert.Equal(t, 1, len(backend.liveness))
169 assert.Equal(t, false, <-backend.liveness)
170 lastUpdateTime := backend.lastLivenessTime
171
172 // Update with changed alive state. Verify alive state push & liveness time update
173 backend.updateLiveness(true)
174 assert.Equal(t, 1, len(backend.liveness))
175 assert.Equal(t, true, <-backend.liveness)
176 assert.NotEqual(t, lastUpdateTime, backend.lastLivenessTime)
177}
178
179// Update Liveness with same alive status reporting
180func TestUpdateLiveness_AliveStatusUnchanged(t *testing.T) {
181 backend := provisionBackendWithEmbeddedEtcdServer(t)
182 // Enable Liveness Channel and verify initial state is not-alive
183 aliveState := backend.EnableLivenessChannel()
184 assert.NotNil(t, aliveState)
185 assert.Equal(t, false, <-backend.liveness)
186 lastUpdateTime := backend.lastLivenessTime
187
188 // Update with same alive state. Verify no further alive state push
189 backend.updateLiveness(false)
190 assert.Equal(t, 0, len(backend.liveness))
191 assert.Equal(t, lastUpdateTime, backend.lastLivenessTime)
192
193 // Now set lastUpdateTime 10 min back and push again
194 tenMinDuration, _ := time.ParseDuration("10m")
195 backend.lastLivenessTime = time.Now().Add(-tenMinDuration)
196 lastUpdateTime = backend.lastLivenessTime
197
198 backend.updateLiveness(false)
199 assert.Equal(t, 1, len(backend.liveness))
200 assert.Equal(t, false, <-backend.liveness)
201 assert.NotEqual(t, lastUpdateTime, backend.lastLivenessTime)
202}
203
204func TestIsErrorIndicatingAliveKvstore(t *testing.T) {
205 tests := []struct {
206 name string
207 arg error
208 want bool
209 }{
210 {"No Error", nil, true},
211 {"Request Canceled", context.Canceled, true},
212 {"Request Timeout", context.DeadlineExceeded, false},
213 {"Etcd Error - InvalidArgument", status.New(codes.InvalidArgument, "").Err(), true},
214 {"Etcd Error - DeadlineExceeded", status.New(codes.DeadlineExceeded, "").Err(), false},
215 {"Etcd Error - Unavailable", status.New(codes.Unavailable, "").Err(), false},
216 {"Etcd Error - DataLoss", status.New(codes.DataLoss, "").Err(), false},
217 {"Etcd Error - NotFound", status.New(codes.NotFound, "").Err(), true},
218 {"Etcd Error - PermissionDenied ", status.New(codes.PermissionDenied, "").Err(), true},
219 {"Etcd Error - FailedPrecondition ", status.New(codes.FailedPrecondition, "").Err(), true},
220 }
221
222 backend := provisionBackendWithEmbeddedEtcdServer(t)
223
224 for _, tt := range tests {
225 t.Run(tt.name, func(t *testing.T) {
226 if backend.isErrorIndicatingAliveKvstore(tt.arg) != tt.want {
227 t.Errorf("isErrorIndicatingAliveKvstore failed for %s: expected %t but got %t", tt.name, tt.want, !tt.want)
228 }
229 })
230 }
231}
232
233func TestPut_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530234 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
235 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000236 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530237 err := backend.Put(ctx, "key1", []uint8("value1"))
Girish Kumarca522102019-11-08 11:26:35 +0000238 assert.Nil(t, err)
239
240 // Assert alive state has become true
241 assert.True(t, backend.alive)
242
243 // Assert that kvstore has this value stored
npujar5bf737f2020-01-16 19:35:25 +0530244 kvpair, err := backend.Get(ctx, "key1")
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800245 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000246 assert.NotNil(t, kvpair)
247 assert.Equal(t, defaultPathPrefix+"/key1", kvpair.Key)
248 assert.Equal(t, []uint8("value1"), kvpair.Value)
249
250 // Assert that Put overrides the Value
npujar5bf737f2020-01-16 19:35:25 +0530251 err = backend.Put(ctx, "key1", []uint8("value11"))
Girish Kumarca522102019-11-08 11:26:35 +0000252 assert.Nil(t, err)
npujar5bf737f2020-01-16 19:35:25 +0530253 kvpair, err = backend.Get(ctx, "key1")
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800254 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000255 assert.NotNil(t, kvpair)
256 assert.Equal(t, defaultPathPrefix+"/key1", kvpair.Key)
257 assert.Equal(t, []uint8("value11"), kvpair.Value)
258}
259
260// Put operation should fail against Dummy Non-existent Etcd Server
261func TestPut_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530262 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
263 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000264 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530265 err := backend.Put(ctx, "key1", []uint8("value1"))
Girish Kumarca522102019-11-08 11:26:35 +0000266 assert.NotNil(t, err)
267
268 // Assert alive state is still false
269 assert.False(t, backend.alive)
270}
271
272// Test Get for existing and non-existing key
273func TestGet_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530274 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
275 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000276 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530277 err := backend.Put(ctx, "key2", []uint8("value2"))
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800278 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000279
280 // Assert alive state has become true
281 assert.True(t, backend.alive)
282
283 // Assert that kvstore has this key stored
npujar5bf737f2020-01-16 19:35:25 +0530284 kvpair, err := backend.Get(ctx, "key2")
Girish Kumarca522102019-11-08 11:26:35 +0000285 assert.NotNil(t, kvpair)
286 assert.Nil(t, err)
287 assert.Equal(t, defaultPathPrefix+"/key2", kvpair.Key)
288 assert.Equal(t, []uint8("value2"), kvpair.Value)
289
290 // Assert that Get works fine for absent key3
npujar5bf737f2020-01-16 19:35:25 +0530291 kvpair, err = backend.Get(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000292 assert.Nil(t, err) // no error as lookup is successful
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800293 assert.Nil(t, kvpair)
Girish Kumarca522102019-11-08 11:26:35 +0000294}
295
296// Get operation should fail against Dummy Non-existent Etcd Server
297func TestGet_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530298 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
299 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000300 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530301 kvpair, err := backend.Get(ctx, "key2")
Girish Kumarca522102019-11-08 11:26:35 +0000302 assert.NotNil(t, err)
303 assert.Nil(t, kvpair)
304
305 // Assert alive state is still false
306 assert.False(t, backend.alive)
307}
308
309// Test Delete for existing and non-existing key
310func TestDelete_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530311 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
312 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000313 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530314 err := backend.Put(ctx, "key3", []uint8("value3"))
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800315 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000316
317 // Assert alive state has become true
318 assert.True(t, backend.alive)
319
320 // Assert that kvstore has this key stored
npujar5bf737f2020-01-16 19:35:25 +0530321 kvpair, err := backend.Get(ctx, "key3")
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800322 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000323 assert.NotNil(t, kvpair)
324
325 // Delete and Assert that key has been removed
npujar5bf737f2020-01-16 19:35:25 +0530326 err = backend.Delete(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000327 assert.Nil(t, err)
npujar5bf737f2020-01-16 19:35:25 +0530328 kvpair, err = backend.Get(ctx, "key3")
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800329 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000330 assert.Nil(t, kvpair)
331
332 // Assert that Delete silently ignores absent key3
npujar5bf737f2020-01-16 19:35:25 +0530333 err = backend.Delete(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000334 assert.Nil(t, err)
335}
336
337// Delete operation should fail against Dummy Non-existent Etcd Server
338func TestDelete_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530339 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
340 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000341 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530342 err := backend.Delete(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000343 assert.NotNil(t, err)
344
345 // Assert alive state is still false
346 assert.False(t, backend.alive)
347}
348
349// Test List for series of values under a key path
350func TestList_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530351 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
352 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000353 key41 := "key4/subkey1"
354 key42 := "key4/subkey2"
355
356 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530357 err := backend.Put(ctx, key41, []uint8("value4-1"))
358 assert.Nil(t, err)
359 err = backend.Put(ctx, key42, []uint8("value4-2"))
360 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000361
362 // Assert alive state has become true
363 assert.True(t, backend.alive)
364
365 // Assert that Get does not retrieve these Subkeys
npujar5bf737f2020-01-16 19:35:25 +0530366 kvpair, err := backend.Get(ctx, "key4")
Girish Kumarca522102019-11-08 11:26:35 +0000367 assert.Nil(t, kvpair)
368 assert.Nil(t, err)
369
370 // Assert that List operation retrieves these Child Keys
npujar5bf737f2020-01-16 19:35:25 +0530371 kvmap, err := backend.List(ctx, "key4")
Girish Kumarca522102019-11-08 11:26:35 +0000372 assert.NotNil(t, kvmap)
373 assert.Nil(t, err)
374 assert.Equal(t, 2, len(kvmap))
375 fullkey41 := defaultPathPrefix + "/" + key41
376 fullkey42 := defaultPathPrefix + "/" + key42
377 assert.Equal(t, fullkey41, kvmap[fullkey41].Key)
378 assert.Equal(t, []uint8("value4-1"), kvmap[fullkey41].Value)
379 assert.Equal(t, fullkey42, kvmap[fullkey42].Key)
380 assert.Equal(t, []uint8("value4-2"), kvmap[fullkey42].Value)
381}
382
383// List operation should fail against Dummy Non-existent Etcd Server
384func TestList_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530385 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
386 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000387 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530388 kvmap, err := backend.List(ctx, "key4")
Girish Kumarca522102019-11-08 11:26:35 +0000389 assert.Nil(t, kvmap)
390 assert.NotNil(t, err)
391
392 // Assert alive state is still false
393 assert.False(t, backend.alive)
394}
395
396// Test Create and Delete Watch for Embedded Etcd Server
397func TestCreateWatch_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530398 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
399 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000400 backend := provisionBackendWithEmbeddedEtcdServer(t)
divyadesai8bf96862020-02-07 12:24:26 +0000401 eventChan := backend.CreateWatch(ctx, "key5", false)
Girish Kumarca522102019-11-08 11:26:35 +0000402 assert.NotNil(t, eventChan)
403 assert.Equal(t, 0, len(eventChan))
404
405 // Assert this method does not change alive state
406 assert.False(t, backend.alive)
407
408 // Put a value for watched key and event should appear
npujar5bf737f2020-01-16 19:35:25 +0530409 err := backend.Put(ctx, "key5", []uint8("value5"))
Girish Kumarca522102019-11-08 11:26:35 +0000410 assert.Nil(t, err)
411 time.Sleep(time.Millisecond * 100)
412 assert.Equal(t, 1, len(eventChan))
413
414 backend.DeleteWatch("key5", eventChan)
415}
divyadesaid737eb62020-03-26 06:52:20 +0000416
417// Test Create and Delete Watch with prefix for Embedded Etcd Server
418func TestCreateWatch_With_Prefix_EmbeddedEtcdServer(t *testing.T) {
419 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
420 defer cancel()
421 backend := provisionBackendWithEmbeddedEtcdServer(t)
422 eventChan := backend.CreateWatch(ctx, "key6", true)
423 assert.NotNil(t, eventChan)
424 assert.Equal(t, 0, len(eventChan))
425
426 // Assert this method does not change alive state
427 assert.False(t, backend.alive)
428
429 // Put a value for watched key and event should appear
430 err := backend.Put(ctx, "key6/is-a-prefix", []uint8("value5"))
431 assert.Nil(t, err)
432 time.Sleep(time.Millisecond * 100)
433 assert.Equal(t, 1, len(eventChan))
434
435 backend.DeleteWatch("key6", eventChan)
436}