blob: b8c66bd2bfa52fbfc11318487ccf08799bad51f1 [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"
khenaidoob6238b32020-04-07 12:07:36 -040021 mocks "github.com/opencord/voltha-lib-go/v3/pkg/mocks/etcd"
khenaidooc7005fc2019-11-18 19:23:57 -050022 "github.com/phayes/freeport"
Girish Kumarca522102019-11-08 11:26:35 +000023 "github.com/stretchr/testify/assert"
24 "google.golang.org/grpc/codes"
25 "google.golang.org/grpc/status"
Neha Sharmadd9af392020-04-28 09:03:57 +000026 "os"
27 "strconv"
28 "testing"
29 "time"
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 {
Neha Sharmadd9af392020-04-28 09:03:57 +000065 backend := NewBackend("etcd", embedEtcdServerHost+":"+strconv.Itoa(embedEtcdServerPort), defaultTimeout, defaultPathPrefix)
Girish Kumarca522102019-11-08 11:26:35 +000066 assert.NotNil(t, backend)
67 assert.NotNil(t, backend.Client)
68 return backend
69}
70
71func provisionBackendWithDummyEtcdServer(t *testing.T) *Backend {
Neha Sharmadd9af392020-04-28 09:03:57 +000072 backend := NewBackend("etcd", embedEtcdServerHost+":"+strconv.Itoa(dummyEtcdServerPort), defaultTimeout, defaultPathPrefix)
Girish Kumarca522102019-11-08 11:26:35 +000073 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) {
Neha Sharmadd9af392020-04-28 09:03:57 +000080 address := embedEtcdServerHost + ":" + strconv.Itoa(embedEtcdServerPort)
81 backend := NewBackend("etcd", address, defaultTimeout, defaultPathPrefix)
Girish Kumarca522102019-11-08 11:26:35 +000082
83 // Verify all attributes of backend have got set correctly
84 assert.NotNil(t, backend)
85 assert.NotNil(t, backend.Client)
86 assert.Equal(t, backend.StoreType, "etcd")
Neha Sharmadd9af392020-04-28 09:03:57 +000087 assert.Equal(t, backend.Address, address)
Girish Kumarca522102019-11-08 11:26:35 +000088 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) {
Neha Sharmadd9af392020-04-28 09:03:57 +000097 backend := NewBackend("consul", embedEtcdServerHost+":"+strconv.Itoa(embedEtcdServerPort), defaultTimeout, defaultPathPrefix)
Girish Kumarca522102019-11-08 11:26:35 +000098
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) {
Neha Sharmadd9af392020-04-28 09:03:57 +0000107 backend := NewBackend("unknown", embedEtcdServerHost+":"+strconv.Itoa(embedEtcdServerPort), defaultTimeout, defaultPathPrefix)
Girish Kumarca522102019-11-08 11:26:35 +0000108
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}