blob: 0da95cd9af884462d504a1f4bee3c476882fc2c7 [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
25 "github.com/opencord/voltha-lib-go/v3/pkg/mocks"
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"
Girish Kumarca522102019-11-08 11:26:35 +000034 defaultTimeout = 1
35 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)
npujar5bf737f2020-01-16 19:35:25 +0530122 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout*time.Second)
123 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)
npujar5bf737f2020-01-16 19:35:25 +0530131 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout*time.Second)
132 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)
npujar5bf737f2020-01-16 19:35:25 +0530151 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout*time.Second)
152 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")
Girish Kumarca522102019-11-08 11:26:35 +0000245 assert.NotNil(t, kvpair)
246 assert.Equal(t, defaultPathPrefix+"/key1", kvpair.Key)
247 assert.Equal(t, []uint8("value1"), kvpair.Value)
248
249 // Assert that Put overrides the Value
npujar5bf737f2020-01-16 19:35:25 +0530250 err = backend.Put(ctx, "key1", []uint8("value11"))
Girish Kumarca522102019-11-08 11:26:35 +0000251 assert.Nil(t, err)
npujar5bf737f2020-01-16 19:35:25 +0530252 kvpair, err = backend.Get(ctx, "key1")
Girish Kumarca522102019-11-08 11:26:35 +0000253 assert.NotNil(t, kvpair)
254 assert.Equal(t, defaultPathPrefix+"/key1", kvpair.Key)
255 assert.Equal(t, []uint8("value11"), kvpair.Value)
256}
257
258// Put operation should fail against Dummy Non-existent Etcd Server
259func TestPut_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530260 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
261 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000262 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530263 err := backend.Put(ctx, "key1", []uint8("value1"))
Girish Kumarca522102019-11-08 11:26:35 +0000264 assert.NotNil(t, err)
265
266 // Assert alive state is still false
267 assert.False(t, backend.alive)
268}
269
270// Test Get for existing and non-existing key
271func TestGet_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530272 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
273 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000274 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530275 err := backend.Put(ctx, "key2", []uint8("value2"))
Girish Kumarca522102019-11-08 11:26:35 +0000276
277 // Assert alive state has become true
278 assert.True(t, backend.alive)
279
280 // Assert that kvstore has this key stored
npujar5bf737f2020-01-16 19:35:25 +0530281 kvpair, err := backend.Get(ctx, "key2")
Girish Kumarca522102019-11-08 11:26:35 +0000282 assert.NotNil(t, kvpair)
283 assert.Nil(t, err)
284 assert.Equal(t, defaultPathPrefix+"/key2", kvpair.Key)
285 assert.Equal(t, []uint8("value2"), kvpair.Value)
286
287 // Assert that Get works fine for absent key3
npujar5bf737f2020-01-16 19:35:25 +0530288 kvpair, err = backend.Get(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000289 assert.Nil(t, kvpair)
290 assert.Nil(t, err) // no error as lookup is successful
291}
292
293// Get operation should fail against Dummy Non-existent Etcd Server
294func TestGet_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530295 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
296 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000297 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530298 kvpair, err := backend.Get(ctx, "key2")
Girish Kumarca522102019-11-08 11:26:35 +0000299 assert.NotNil(t, err)
300 assert.Nil(t, kvpair)
301
302 // Assert alive state is still false
303 assert.False(t, backend.alive)
304}
305
306// Test Delete for existing and non-existing key
307func TestDelete_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530308 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
309 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000310 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530311 err := backend.Put(ctx, "key3", []uint8("value3"))
Girish Kumarca522102019-11-08 11:26:35 +0000312
313 // Assert alive state has become true
314 assert.True(t, backend.alive)
315
316 // Assert that kvstore has this key stored
npujar5bf737f2020-01-16 19:35:25 +0530317 kvpair, err := backend.Get(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000318 assert.NotNil(t, kvpair)
319
320 // Delete and Assert that key has been removed
npujar5bf737f2020-01-16 19:35:25 +0530321 err = backend.Delete(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000322 assert.Nil(t, err)
npujar5bf737f2020-01-16 19:35:25 +0530323 kvpair, err = backend.Get(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000324 assert.Nil(t, kvpair)
325
326 // Assert that Delete silently ignores absent key3
npujar5bf737f2020-01-16 19:35:25 +0530327 err = backend.Delete(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000328 assert.Nil(t, err)
329}
330
331// Delete operation should fail against Dummy Non-existent Etcd Server
332func TestDelete_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530333 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
334 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000335 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530336 err := backend.Delete(ctx, "key3")
Girish Kumarca522102019-11-08 11:26:35 +0000337 assert.NotNil(t, err)
338
339 // Assert alive state is still false
340 assert.False(t, backend.alive)
341}
342
343// Test List for series of values under a key path
344func TestList_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530345 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
346 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000347 key41 := "key4/subkey1"
348 key42 := "key4/subkey2"
349
350 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530351 err := backend.Put(ctx, key41, []uint8("value4-1"))
352 assert.Nil(t, err)
353 err = backend.Put(ctx, key42, []uint8("value4-2"))
354 assert.Nil(t, err)
Girish Kumarca522102019-11-08 11:26:35 +0000355
356 // Assert alive state has become true
357 assert.True(t, backend.alive)
358
359 // Assert that Get does not retrieve these Subkeys
npujar5bf737f2020-01-16 19:35:25 +0530360 kvpair, err := backend.Get(ctx, "key4")
Girish Kumarca522102019-11-08 11:26:35 +0000361 assert.Nil(t, kvpair)
362 assert.Nil(t, err)
363
364 // Assert that List operation retrieves these Child Keys
npujar5bf737f2020-01-16 19:35:25 +0530365 kvmap, err := backend.List(ctx, "key4")
Girish Kumarca522102019-11-08 11:26:35 +0000366 assert.NotNil(t, kvmap)
367 assert.Nil(t, err)
368 assert.Equal(t, 2, len(kvmap))
369 fullkey41 := defaultPathPrefix + "/" + key41
370 fullkey42 := defaultPathPrefix + "/" + key42
371 assert.Equal(t, fullkey41, kvmap[fullkey41].Key)
372 assert.Equal(t, []uint8("value4-1"), kvmap[fullkey41].Value)
373 assert.Equal(t, fullkey42, kvmap[fullkey42].Key)
374 assert.Equal(t, []uint8("value4-2"), kvmap[fullkey42].Value)
375}
376
377// List operation should fail against Dummy Non-existent Etcd Server
378func TestList_DummyEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530379 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
380 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000381 backend := provisionBackendWithDummyEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530382 kvmap, err := backend.List(ctx, "key4")
Girish Kumarca522102019-11-08 11:26:35 +0000383 assert.Nil(t, kvmap)
384 assert.NotNil(t, err)
385
386 // Assert alive state is still false
387 assert.False(t, backend.alive)
388}
389
390// Test Create and Delete Watch for Embedded Etcd Server
391func TestCreateWatch_EmbeddedEtcdServer(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530392 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
393 defer cancel()
Girish Kumarca522102019-11-08 11:26:35 +0000394 backend := provisionBackendWithEmbeddedEtcdServer(t)
npujar5bf737f2020-01-16 19:35:25 +0530395 eventChan := backend.CreateWatch(ctx, "key5")
Girish Kumarca522102019-11-08 11:26:35 +0000396 assert.NotNil(t, eventChan)
397 assert.Equal(t, 0, len(eventChan))
398
399 // Assert this method does not change alive state
400 assert.False(t, backend.alive)
401
402 // Put a value for watched key and event should appear
npujar5bf737f2020-01-16 19:35:25 +0530403 err := backend.Put(ctx, "key5", []uint8("value5"))
Girish Kumarca522102019-11-08 11:26:35 +0000404 assert.Nil(t, err)
405 time.Sleep(time.Millisecond * 100)
406 assert.Equal(t, 1, len(eventChan))
407
408 backend.DeleteWatch("key5", eventChan)
409}