github.com/portworx/kvdb@v0.0.0-20241107215734-a185a966f535/test/kv.go (about)

     1  package test
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"math/rand"
     8  	"sort"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"sync/atomic"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/portworx/kvdb"
    17  	_ "github.com/portworx/kvdb/wrappers"
    18  	"github.com/sirupsen/logrus"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  type watchData struct {
    24  	t            *testing.T
    25  	key          string
    26  	otherKey     string
    27  	stop         string
    28  	localIndex   uint64
    29  	updateIndex  uint64
    30  	kvp          *kvdb.KVPair
    31  	watchStopped bool
    32  	iterations   int
    33  	action       kvdb.KVAction
    34  	writer       int32
    35  	reader       int32
    36  	whichKey     int32
    37  }
    38  
    39  type lockTag struct {
    40  	nodeID   string
    41  	funcName string
    42  }
    43  
    44  func fatalErrorCb() kvdb.FatalErrorCB {
    45  	return func(err error, format string, args ...interface{}) {
    46  	}
    47  }
    48  
    49  // StartKvdb is a func literal.
    50  type StartKvdb func(bool) error
    51  
    52  // StopKvdb is a func literal.
    53  type StopKvdb func() error
    54  
    55  // Run runs the test suite.
    56  func Run(datastoreInit kvdb.DatastoreInit, t *testing.T, start StartKvdb, stop StopKvdb) {
    57  	err := start(true)
    58  	assert.NoError(t, err, "Unable to start kvdb")
    59  	// Wait for kvdb to start
    60  	time.Sleep(5 * time.Second)
    61  	kv, err := datastoreInit("pwx/test", nil, nil, fatalErrorCb())
    62  	if err != nil {
    63  		t.Fatalf(err.Error())
    64  	}
    65  	create(kv, t)
    66  	createWithTTL(kv, t)
    67  	cas(kv, t)
    68  	cad(kv, t)
    69  	snapshot(kv, t)
    70  	get(kv, t)
    71  	getInterface(kv, t)
    72  	update(kv, t)
    73  	deleteKey(kv, t)
    74  	deleteTree(kv, t)
    75  	enumerate(kv, t)
    76  	keys(kv, t)
    77  	concurrentEnum(kv, t)
    78  	watchKey(kv, t)
    79  	watchTree(kv, t)
    80  	watchWithIndex(kv, t)
    81  	collect(kv, t)
    82  	lockTimeoutError(kv, t)
    83  	lockBasic(kv, t)
    84  	lock(kv, t)
    85  	lockBetweenRestarts(kv, t, start, stop)
    86  	serialization(kv, t)
    87  	err = stop()
    88  	assert.NoError(t, err, "Unable to stop kvdb")
    89  
    90  	// ensure wrapper does not crash when kvdb members are stopped.
    91  	wrapper, err := kvdb.AddWrapper(kvdb.Wrapper_Log, kv, nil)
    92  	assert.NoError(t, err, "add log wrapper")
    93  	assert.Equal(t, kvdb.Wrapper_Log, wrapper.WrapperName(), "get log wrapper name")
    94  	wrapper, err = kvdb.AddWrapper(kvdb.Wrapper_NoQuorum, wrapper, nil)
    95  	assert.NoError(t, err, "add quorum wrapper")
    96  	assert.Equal(t, kvdb.Wrapper_Log, wrapper.WrapperName(), "log wrapper must be at top")
    97  	assert.Equal(t, kvdb.Wrapper_NoQuorum,
    98  		wrapper.WrappedKvdb().WrapperName(),
    99  		"quorum wrapper found")
   100  	noQuorum(wrapper, t)
   101  
   102  	// remove wrapper
   103  	wrapper, err = kvdb.RemoveWrapper(kvdb.Wrapper_NoQuorum, wrapper)
   104  	assert.NoError(t, err, "remove quorum filter wrapper")
   105  	assert.Equal(t, kvdb.Wrapper_Log, wrapper.WrapperName(), "get log wrapper name")
   106  	assert.Equal(t, kvdb.Wrapper_None, wrapper.WrappedKvdb().WrapperName(),
   107  		"quorum wrapper removed")
   108  
   109  	// add quorum wrapper again
   110  	wrapper, err = kvdb.AddWrapper(kvdb.Wrapper_NoQuorum, wrapper, nil)
   111  	assert.NoError(t, err, "add quorum wrapper")
   112  	assert.Equal(t, kvdb.Wrapper_Log, wrapper.WrapperName(), "log wrapper must be at top")
   113  	assert.Equal(t, kvdb.Wrapper_NoQuorum,
   114  		wrapper.WrappedKvdb().WrapperName(),
   115  		"quorum wrapper found")
   116  	noQuorum(wrapper, t)
   117  
   118  	// remove all wrappers
   119  	wrapper, err = kvdb.RemoveWrapper(kvdb.Wrapper_Log, wrapper)
   120  	assert.NoError(t, err, "remove quorum filter wrapper")
   121  	wrapper, err = kvdb.RemoveWrapper(kvdb.Wrapper_NoQuorum, wrapper)
   122  	assert.NoError(t, err, "remove quorum filter wrapper")
   123  	assert.Equal(t, kvdb.Wrapper_None, wrapper.WrapperName(), "quorum wrapper removed")
   124  }
   125  
   126  // RunBasic runs the basic test suite.
   127  func RunBasic(datastoreInit kvdb.DatastoreInit, t *testing.T, start StartKvdb, stop StopKvdb) {
   128  	err := start(true)
   129  	assert.NoError(t, err, "Unable to start kvdb")
   130  	// Wait for kvdb to start
   131  	time.Sleep(5 * time.Second)
   132  	kv, err := datastoreInit("pwx/test", nil, nil, fatalErrorCb())
   133  	if err != nil {
   134  		t.Fatalf(err.Error())
   135  	}
   136  	create(kv, t)
   137  	cas(kv, t)
   138  	cad(kv, t)
   139  	get(kv, t)
   140  	getInterface(kv, t)
   141  	update(kv, t)
   142  	deleteKey(kv, t)
   143  	deleteTree(kv, t)
   144  	enumerate(kv, t)
   145  	keys(kv, t)
   146  	lockBasic(kv, t)
   147  	lock(kv, t)
   148  	err = stop()
   149  	assert.NoError(t, err, "Unable to stop kvdb")
   150  }
   151  
   152  // RunLock runs the lock test suite.
   153  func RunLock(datastoreInit kvdb.DatastoreInit, t *testing.T, start StartKvdb, stop StopKvdb) {
   154  	err := start(true)
   155  	time.Sleep(3 * time.Second)
   156  	assert.NoError(t, err, "Unable to start kvdb")
   157  	kv, err := datastoreInit("pwx/test", nil, nil, fatalErrorCb())
   158  	if err != nil {
   159  		t.Fatalf(err.Error())
   160  	}
   161  
   162  	lockBasic(kv, t)
   163  	lock(kv, t)
   164  	lockBetweenRestarts(kv, t, start, stop)
   165  
   166  	err = stop()
   167  	assert.NoError(t, err, "Unable to stop kvdb")
   168  }
   169  
   170  // RunWatch runs the watch test suite.
   171  func RunWatch(datastoreInit kvdb.DatastoreInit, t *testing.T, start StartKvdb, stop StopKvdb) {
   172  	err := start(true)
   173  	time.Sleep(3 * time.Second)
   174  	assert.NoError(t, err, "Unable to start kvdb")
   175  	kv, err := datastoreInit("pwx/test", nil, nil, fatalErrorCb())
   176  	if err != nil {
   177  		t.Fatalf(err.Error())
   178  	}
   179  
   180  	// watchKey(kv, t)
   181  	// watchTree(kv, t)
   182  	// watchWithIndex(kv, t)
   183  	collect(kv, t)
   184  	// serialization(kv, t)
   185  	// concurrentEnum(kv, t)
   186  
   187  	err = stop()
   188  	assert.NoError(t, err, "Unable to stop kvdb")
   189  }
   190  
   191  // RunAuth runs the authentication test suite for kvdb
   192  func RunAuth(datastoreInit kvdb.DatastoreInit, t *testing.T) {
   193  	options := make(map[string]string)
   194  	// In order to run these tests, either configure your local etcd
   195  	// to use these options (username/password/ca-file) or modify them here.
   196  	options[kvdb.UsernameKey] = "root"
   197  	kv, err := datastoreInit("pwx/test", nil, options, fatalErrorCb())
   198  	if err == nil {
   199  		t.Fatalf("Expected an error when no password provided")
   200  	}
   201  	options[kvdb.PasswordKey] = "test123"
   202  	kv, err = datastoreInit("pwx/test", nil, options, fatalErrorCb())
   203  	if err == nil {
   204  		t.Fatalf("Expected an error when no certificate provided")
   205  	}
   206  	options[kvdb.CAFileKey] = "/etc/pwx/pwx-ca.crt"
   207  	options[kvdb.CertFileKey] = "/etc/pwx/pwx-user-cert.crt"
   208  	options[kvdb.CertKeyFileKey] = "/etc/pwx/pwx-user-key.key"
   209  
   210  	machines := []string{"https://192.168.56.101:2379"}
   211  	fmt.Println("Last one")
   212  	kv, err = datastoreInit("pwx/test", machines, options, fatalErrorCb())
   213  	if err != nil {
   214  		t.Fatalf(err.Error())
   215  	}
   216  	if kv == nil {
   217  		t.Fatalf("Expected kv to be not nil")
   218  	}
   219  	// Run the basic put get update tests using auth
   220  	get(kv, t)
   221  	create(kv, t)
   222  	update(kv, t)
   223  	// Run the auth tests
   224  	addUser(kv, t)
   225  	grantRevokeUser(kv, datastoreInit, t)
   226  	removeUser(kv, t)
   227  }
   228  
   229  func get(kv kvdb.Kvdb, t *testing.T) {
   230  	fmt.Println("get")
   231  
   232  	kvPair, err := kv.Get("DEADCAFE")
   233  	assert.Error(t, err, "Expecting error value for non-existent value")
   234  
   235  	key := "foo/docker"
   236  	val := "great"
   237  	defer func() {
   238  		kv.Delete(key)
   239  	}()
   240  
   241  	kvPair, err = kv.Put(key, []byte(val), 0)
   242  	assert.NoError(t, err, "Unexpected error in Put")
   243  
   244  	kvPair, err = kv.Get(key)
   245  	assert.NoError(t, err, "Failed in Get")
   246  
   247  	assert.Equal(t, key, kvPair.Key, "Key mismatch in Get")
   248  	assert.Equal(t, string(kvPair.Value), val, "value mismatch in Get")
   249  }
   250  
   251  func getInterface(kv kvdb.Kvdb, t *testing.T) {
   252  
   253  	fmt.Println("getInterface")
   254  	expected := struct {
   255  		N int
   256  		S string
   257  	}{
   258  		N: 10,
   259  		S: "Ten",
   260  	}
   261  
   262  	actual := expected
   263  	actual.N = 0
   264  	actual.S = "zero"
   265  
   266  	key := "DEADBEEF"
   267  	_, err := kv.Delete(key)
   268  	_, err = kv.Put(key, &expected, 0)
   269  	assert.NoError(t, err, "Failed in Put")
   270  
   271  	_, err = kv.GetVal(key, &actual)
   272  	assert.NoError(t, err, "Failed in Get")
   273  
   274  	assert.Equal(t, expected, actual, "Expected %#v but got %#v",
   275  		expected, actual)
   276  }
   277  
   278  func create(kv kvdb.Kvdb, t *testing.T) {
   279  	fmt.Println("create")
   280  
   281  	key := "///create/foo"
   282  	kv.Delete(key)
   283  
   284  	kvp, err := kv.Create(key, []byte("bar"), 0)
   285  	require.NoError(t, err, "Error on create")
   286  
   287  	defer func() {
   288  		kv.Delete(key)
   289  	}()
   290  	assert.Equal(t, kvp.Action, kvdb.KVCreate,
   291  		"Expected action KVCreate, actual %v", kvp.Action)
   292  
   293  	_, err = kv.Create(key, []byte("bar"), 0)
   294  	assert.True(t, err == kvdb.ErrExist,
   295  		"Create on existing key should have errored.")
   296  }
   297  
   298  func createWithTTL(kv kvdb.Kvdb, t *testing.T) {
   299  	fmt.Println("create with ttl")
   300  	key := "create/foottl"
   301  	kv.Delete(key)
   302  	assert.NotNil(t, kv, "Default KVDB is not set")
   303  	_, err := kv.Create(key, []byte("bar"), 6)
   304  	if err != nil {
   305  		// Consul does not support ttl less than 10
   306  		assert.EqualError(t, err, kvdb.ErrTTLNotSupported.Error(), "ttl not supported")
   307  		_, err := kv.Create(key, []byte("bar"), 20)
   308  		assert.NoError(t, err, "Error on create")
   309  		// Consul doubles the ttl value
   310  		time.Sleep(time.Second * 21)
   311  		_, err = kv.Get(key)
   312  		assert.Error(t, err, "Expecting error value for expired value")
   313  
   314  	} else {
   315  		assert.NoError(t, err, "Error on create")
   316  		time.Sleep(time.Second * 7)
   317  		_, err = kv.Get(key)
   318  		assert.Error(t, err, "Expecting error value for expired value")
   319  	}
   320  }
   321  
   322  func update(kv kvdb.Kvdb, t *testing.T) {
   323  	fmt.Println("update")
   324  
   325  	key := "update/foo"
   326  	kv.Delete(key)
   327  
   328  	kvp, err := kv.Update(key, []byte("bar"), 0)
   329  	assert.Error(t, err, "Update should error on non-existent key")
   330  
   331  	defer func() {
   332  		kv.Delete(key)
   333  	}()
   334  
   335  	kvp, err = kv.Create(key, []byte("bar"), 0)
   336  	assert.NoError(t, err, "Unexpected error on create")
   337  
   338  	kvp, err = kv.Update(key, []byte("bar"), 0)
   339  	assert.NoError(t, err, "Unexpected error on update")
   340  
   341  	assert.Equal(t, kvp.Action, kvdb.KVSet,
   342  		"Expected action KVSet, actual %v", kvp.Action)
   343  }
   344  
   345  func deleteKey(kv kvdb.Kvdb, t *testing.T) {
   346  	fmt.Println("deleteKey")
   347  
   348  	key := "delete_key"
   349  	_, err := kv.Delete(key)
   350  
   351  	_, err = kv.Put(key, []byte("delete_me"), 0)
   352  	assert.NoError(t, err, "Unexpected error on Put")
   353  
   354  	_, err = kv.Get(key)
   355  	assert.NoError(t, err, "Unexpected error on Get")
   356  
   357  	_, err = kv.Delete(key)
   358  	assert.NoError(t, err, "Unexpected error on Delete")
   359  
   360  	_, err = kv.Get(key)
   361  	assert.Error(t, err, "Get should fail on deleted key")
   362  
   363  	_, err = kv.Delete(key)
   364  	assert.Error(t, err, "Delete should fail on non existent key")
   365  	assert.EqualError(t, err, kvdb.ErrNotFound.Error(), "Invalid error returned : %v", err)
   366  }
   367  
   368  func deleteTree(kv kvdb.Kvdb, t *testing.T) {
   369  	fmt.Println("deleteTree")
   370  
   371  	prefix := "tree"
   372  	keys := map[string]string{
   373  		prefix + "/1cbc9a98-072a-4793-8608-01ab43db96c8": "bar",
   374  		prefix + "/foo": "baz",
   375  	}
   376  
   377  	for key, val := range keys {
   378  		_, err := kv.Put(key, []byte(val), 0)
   379  		assert.NoError(t, err, "Unexpected error on Put")
   380  	}
   381  
   382  	keyWithSamePrefix := prefix + "_some"
   383  	_, err := kv.Put(keyWithSamePrefix, []byte("val"), 0)
   384  	assert.NoError(t, err, "Unexpected error on Put")
   385  
   386  	_, err = kv.Get(keyWithSamePrefix)
   387  	assert.NoError(t, err, "Unexpected error on Get")
   388  
   389  	for key := range keys {
   390  		_, err := kv.Get(key)
   391  		assert.NoError(t, err, "Unexpected error on Get")
   392  	}
   393  	err = kv.DeleteTree(prefix)
   394  	assert.NoError(t, err, "Unexpected error on DeleteTree")
   395  
   396  	for key := range keys {
   397  		_, err := kv.Get(key)
   398  		assert.Error(t, err, "Get should fail on all keys after DeleteTree")
   399  	}
   400  	_, err = kv.Get(keyWithSamePrefix)
   401  	assert.NoError(t, err, "Unexpected error on Get")
   402  }
   403  
   404  func enumerate(kv kvdb.Kvdb, t *testing.T) {
   405  
   406  	fmt.Println("enumerate")
   407  
   408  	prefix := "enumerate"
   409  	keys := map[string]string{
   410  		prefix + "/1cbc9a98-072a-4793-8608-01ab43db96c8": "bar",
   411  		prefix + "/foo": "baz",
   412  	}
   413  
   414  	kv.DeleteTree(prefix)
   415  	defer func() {
   416  		kv.DeleteTree(prefix)
   417  	}()
   418  
   419  	errPairs, err := kv.Enumerate(prefix)
   420  	assert.Equal(t, 0, len(errPairs), "Expected 0 pairs")
   421  
   422  	folderKey := prefix + "/folder/"
   423  	_, err = kv.Put(folderKey, []byte("value"), 0)
   424  	assert.NoError(t, err, "Unexpected error on Put")
   425  	kvPairs, err := kv.Enumerate(folderKey)
   426  	assert.NoError(t, err, "Unexpected error on Enumerate")
   427  	kv.DeleteTree(prefix)
   428  
   429  	for key, val := range keys {
   430  		_, err := kv.Put(key, []byte(val), 0)
   431  		assert.NoError(t, err, "Unexpected error on Put")
   432  	}
   433  	kvPairs, err = kv.Enumerate(prefix)
   434  	assert.NoError(t, err, "Unexpected error on Enumerate")
   435  
   436  	assert.Equal(t, len(kvPairs), len(keys),
   437  		"Expecting %d keys under %s got: %d",
   438  		len(keys), prefix, len(kvPairs))
   439  
   440  	for i := range kvPairs {
   441  		v, ok := keys[kvPairs[i].Key]
   442  		assert.True(t, ok, "unexpected kvpair (%s)->(%s)",
   443  			kvPairs[i].Key, kvPairs[i].Value)
   444  		assert.Equal(t, v, string(kvPairs[i].Value),
   445  			"Invalid kvpair (%s)->(%s) expect value %s",
   446  			kvPairs[i].Key, kvPairs[i].Value, v)
   447  	}
   448  }
   449  
   450  func keys(kv kvdb.Kvdb, t *testing.T) {
   451  
   452  	fmt.Println("keys")
   453  
   454  	prefix := "keys"
   455  	testKeys := []string{"testkey1", "testkey2", "testkey99999999999999999"}
   456  	testRows := map[string]string{
   457  		prefix + "/" + testKeys[0]:                    "bar",
   458  		prefix + "/" + testKeys[1] + "/testkey3":      "baz",
   459  		prefix + "/" + testKeys[2] + "/here/or/there": "foo",
   460  	}
   461  
   462  	kv.DeleteTree(prefix)
   463  	defer func() {
   464  		kv.DeleteTree(prefix)
   465  	}()
   466  
   467  	keys, err := kv.Keys(prefix, "")
   468  	assert.Equal(t, 0, len(keys), "Expected 0 keys")
   469  
   470  	for key, val := range testRows {
   471  		_, err := kv.Put(key, []byte(val), 0)
   472  		assert.NoError(t, err, "Unexpected error on Put")
   473  	}
   474  
   475  	keys, err = kv.Keys(prefix, "")
   476  	assert.NoError(t, err, "Unexpected error on Keys")
   477  
   478  	assert.Equal(t, len(testRows), len(keys),
   479  		"Expecting %d keys under %s got: %d",
   480  		len(testRows), prefix, len(keys))
   481  
   482  	sort.Strings(keys)
   483  	sort.Strings(testKeys)
   484  	assert.Equal(t, testKeys, keys,
   485  		"Expecting array %v to be equal to %v",
   486  		testKeys, keys)
   487  }
   488  
   489  func concurrentEnum(kv kvdb.Kvdb, t *testing.T) {
   490  
   491  	fmt.Println("concurrentEnum")
   492  
   493  	prefix := "concEnum"
   494  	var wg sync.WaitGroup
   495  	quit, latch := make(chan bool), make(chan bool)
   496  	shared, numGoroutines := int32(0), 0
   497  
   498  	kv.DeleteTree(prefix)
   499  	defer func() {
   500  		kv.DeleteTree(prefix)
   501  	}()
   502  
   503  	// start 3 "adders"
   504  	for i := 0; i < 3; i++ {
   505  		go func() {
   506  			id := atomic.AddInt32(&shared, 1)
   507  			fmt.Printf("+> Adder #%d started\n", id)
   508  			content := []byte(fmt.Sprintf("adder #%d", id))
   509  			wg.Add(1)
   510  			defer wg.Done()
   511  			_ = <-latch // sync-point
   512  			numFails := 0
   513  			for j := 0; ; j++ {
   514  				select {
   515  				case <-quit:
   516  					fmt.Printf("+> Adder #%d quit (stored %d keys)\n", id, j)
   517  					return
   518  				default:
   519  					key := fmt.Sprintf("%s/%d-%d", prefix, id, j%100000)
   520  					_, err := kv.Put(key, content, 0)
   521  					if err != nil {
   522  						logrus.WithError(err).Warnf("Error inserting key %s", key)
   523  						numFails++
   524  						// let's tolerate some errors, since we're in race w/ Deleter
   525  						assert.True(t, numFails < 10, "Too many failures on PUT")
   526  					}
   527  					// sleep a bit, not to be overly aggressive
   528  					time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
   529  				}
   530  			}
   531  		}()
   532  		numGoroutines++
   533  	}
   534  
   535  	// start 1 "deleter"
   536  	go func() {
   537  		wg.Add(1)
   538  		defer wg.Done()
   539  		fmt.Printf("+> Deleter started\n")
   540  		_ = <-latch     // sync-point
   541  		for j := 0; ; { // cap at max 100k
   542  			select {
   543  			case <-quit:
   544  				fmt.Printf("+> Deleter quit (deleted %d keys)\n", j)
   545  				return
   546  			default:
   547  				key := fmt.Sprintf("%s/%d-%d", prefix, rand.Intn(numGoroutines), j%100000)
   548  				_, err := kv.Delete(key)
   549  				if err == nil {
   550  					// advance only on successful delete
   551  					j++
   552  				}
   553  				// sleep a bit, not to be overly aggressive
   554  				time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
   555  			}
   556  		}
   557  	}()
   558  	numGoroutines++
   559  
   560  	fmt.Printf("> MAIN waiting for workers\n")
   561  	time.Sleep(50 * time.Millisecond)
   562  	close(latch) // release sync-points
   563  	time.Sleep(5500 * time.Millisecond)
   564  
   565  	// make sure these two just work, otherwise we cannot assume how many elements found
   566  
   567  	sep := ':'
   568  	fmt.Printf("> MAIN run")
   569  	for i := 0; i < 5; i++ {
   570  		fmt.Printf("%c Enumerate", sep)
   571  		_, err := kv.Enumerate(prefix)
   572  		assert.NoError(t, err)
   573  
   574  		sep = ','
   575  		fmt.Printf("%c Keys", sep)
   576  		_, err = kv.Keys(prefix, "")
   577  		assert.NoError(t, err)
   578  	}
   579  
   580  	fmt.Printf("%c stop workers\n", sep)
   581  	for i := 0; i < numGoroutines; i++ {
   582  		quit <- true
   583  	}
   584  	close(quit)
   585  	fmt.Printf("> MAIN waiting ...")
   586  	wg.Wait()
   587  	fmt.Printf("DONE.\n")
   588  }
   589  
   590  func snapshot(kv kvdb.Kvdb, t *testing.T) {
   591  	fmt.Println("snapshot")
   592  
   593  	prefix := "snapshot/"
   594  	kv.DeleteTree(prefix)
   595  	defer kv.DeleteTree(prefix)
   596  
   597  	prefix2 := "snapshot2/"
   598  	kv.DeleteTree(prefix2)
   599  	defer kv.DeleteTree(prefix2)
   600  
   601  	prefix3 := "snapshot2/subtree/"
   602  
   603  	ignorePrefix := "ignoreSnapshot/"
   604  	kv.DeleteTree(ignorePrefix)
   605  	defer kv.DeleteTree(ignorePrefix)
   606  
   607  	preSnapData := make(map[string]string)
   608  	preSnapDataVersion := make(map[string]uint64)
   609  	inputData := make(map[string]string)
   610  	inputDataVersion := make(map[string]uint64)
   611  	deleteKeys := make(map[string]string)
   612  
   613  	key := "key"
   614  	value := "bar"
   615  	keyd := "key-delete"
   616  	valued := "bar-delete"
   617  	count := 100
   618  	doneUpdate := make(chan bool, 2)
   619  	emptyKeyName := ""
   620  	updateFn := func(count int, v string, dataMap map[string]string,
   621  		versionMap map[string]uint64, isDelete bool) {
   622  		for i := 0; i < count; i++ {
   623  			suffix := strconv.Itoa(i)
   624  			var inputKey string
   625  			if i%3 == 0 {
   626  				inputKey = prefix + key + suffix
   627  			} else if i%3 == 1 {
   628  				inputKey = prefix3 + key + suffix
   629  			} else {
   630  				inputKey = prefix2 + key + suffix
   631  			}
   632  			inputValue := v
   633  			if i == 0 {
   634  				emptyKeyName = inputKey
   635  				inputValue = ""
   636  			}
   637  			kvp, err := kv.Put(inputKey, []byte(inputValue), 0)
   638  			assert.NoError(t, err, "Unexpected error on Put")
   639  			dataMap[inputKey] = inputValue
   640  			versionMap[inputKey] = kvp.ModifiedIndex
   641  			deleteKey := prefix + keyd + suffix
   642  			if !isDelete {
   643  				_, err := kv.Put(deleteKey, []byte(valued), 0)
   644  				assert.NoError(t, err, "Unexpected error on Put")
   645  				deleteKeys[deleteKey] = deleteKey
   646  			} else {
   647  				_, err := kv.Delete(deleteKey)
   648  				assert.NoError(t, err, "Unexpected error on Delete")
   649  			}
   650  
   651  			// update ops on keys which need to be ignore
   652  			inputKey = ignorePrefix + key + suffix
   653  			_, err = kv.Put(inputKey, []byte(inputValue), 0)
   654  			assert.NoError(t, err, "Unexpected error on Put")
   655  
   656  			deleteKey = ignorePrefix + keyd + suffix
   657  			if !isDelete {
   658  				_, err := kv.Put(deleteKey, []byte(valued), 0)
   659  				assert.NoError(t, err, "Unexpected error on Put")
   660  			} else {
   661  				_, err := kv.Delete(deleteKey)
   662  				assert.NoError(t, err, "Unexpected error on Delete")
   663  			}
   664  		}
   665  		doneUpdate <- true
   666  	}
   667  
   668  	updateFn(count, value, preSnapData, preSnapDataVersion, false)
   669  	<-doneUpdate
   670  	newValue := "bar2"
   671  	go updateFn(count, newValue, inputData, inputDataVersion, true)
   672  	time.Sleep(20 * time.Millisecond)
   673  
   674  	snap, snapVersion, err := kv.Snapshot([]string{prefix, prefix2, prefix3}, true)
   675  	assert.NoError(t, err, "Unexpected error on Snapshot")
   676  	<-doneUpdate
   677  
   678  	// Enumerate on prefix 1
   679  	kvps, err := snap.Enumerate(prefix)
   680  	assert.NoError(t, err, "Unexpected error on Enumerate")
   681  
   682  	// Enumerate on prefix 2
   683  	kvps2, err := snap.Enumerate(prefix2)
   684  	assert.NoError(t, err, "Unexpected error on Enumerate")
   685  
   686  	kvPairs := append(kvps, kvps2...)
   687  
   688  	processedKeys := 0
   689  	for i := range kvPairs {
   690  		if strings.Contains(kvPairs[i].Key, keyd) {
   691  			_, ok := deleteKeys[kvPairs[i].Key]
   692  			assert.True(t, ok, "Key not found in deleteKeys list (%v)", kvPairs[i].Key)
   693  			delete(deleteKeys, kvPairs[i].Key)
   694  			continue
   695  		}
   696  		processedKeys++
   697  		currValue, ok1 := inputData[kvPairs[i].Key]
   698  		currVersion, ok2 := inputDataVersion[kvPairs[i].Key]
   699  		preSnapValue, ok3 := preSnapData[kvPairs[i].Key]
   700  		preSnapKeyVersion, ok4 := preSnapDataVersion[kvPairs[i].Key]
   701  		assert.True(t, ok1 && ok2 && ok3 && ok4, "unexpected kvpair (%s)->(%s)",
   702  			kvPairs[i].Key, kvPairs[i].Value)
   703  
   704  		assert.True(t, kvPairs[i].Key == emptyKeyName ||
   705  			len(string(kvPairs[i].Value)) != 0,
   706  			"Empty value for key %f", kvPairs[i].Key)
   707  
   708  		assert.True(t, kvPairs[i].ModifiedIndex < snapVersion,
   709  			"snap db key (%v) has version greater than snap version (%v)",
   710  			kvPairs[i].ModifiedIndex, snapVersion)
   711  
   712  		if kvPairs[i].ModifiedIndex == currVersion {
   713  			assert.True(t, string(kvPairs[i].Value) == currValue,
   714  				"snapshot db does not have correct value, "+
   715  					" expected %v got %v", currValue, string(kvPairs[i].Value))
   716  		} else {
   717  			assert.True(t, kvPairs[i].ModifiedIndex == preSnapKeyVersion,
   718  				"snapshot db does not have correct version, expected %v got %v",
   719  				kvPairs[i].ModifiedIndex, preSnapKeyVersion)
   720  			assert.True(t, string(kvPairs[i].Value) == preSnapValue,
   721  				"snapshot db does not have correct value, "+
   722  					" expected %v got %v", preSnapValue, string(kvPairs[i].Value))
   723  		}
   724  	}
   725  	assert.Equal(t, count, processedKeys,
   726  		"Expecting %d keys under %s got: %d, kv: %v",
   727  		processedKeys, prefix, len(kvPairs), kvPairs)
   728  
   729  	// Check there are no keys under the ignored prefix
   730  	kvPairs, err = snap.Enumerate(ignorePrefix)
   731  	assert.Equal(t, 0, len(kvPairs), "Expected 0 pairs to be returned under the ignored prefix")
   732  }
   733  
   734  func getLockMethods(kv kvdb.Kvdb) []func(string) (*kvdb.KVPair, error) {
   735  	lockMethods := make([]func(string) (*kvdb.KVPair, error), 2)
   736  	lockMethods[0] = func(key string) (*kvdb.KVPair, error) {
   737  		return kv.Lock(key)
   738  	}
   739  	lockMethods[1] = func(key string) (*kvdb.KVPair, error) {
   740  		tag := "node:node_1,func:testfunc"
   741  		return kv.LockWithID(key, tag)
   742  	}
   743  	return lockMethods
   744  }
   745  
   746  func lock(kv kvdb.Kvdb, t *testing.T) {
   747  	lockMethods := getLockMethods(kv)
   748  
   749  	for _, lockMethod := range lockMethods {
   750  		kv.SetLockHoldDuration(time.Duration(0))
   751  		fmt.Println("lock")
   752  
   753  		key := "locktest"
   754  		kvPair, err := lockMethod(key)
   755  		assert.NoError(t, err, "Unexpected error in lock")
   756  
   757  		if kvPair == nil {
   758  			return
   759  		}
   760  
   761  		// For consul unlock does not deal with the value part of the kvPair
   762  		/*
   763  			stash := *kvPair
   764  			stash.Value = []byte("hoohah")
   765  			fmt.Println("bad unlock")
   766  			err = kv.Unlock(&stash)
   767  			assert.Error(t, err, "Unlock should fail for bad KVPair")
   768  		*/
   769  
   770  		fmt.Println("unlock")
   771  		err = kv.Unlock(kvPair)
   772  		assert.NoError(t, err, "Unexpected error from Unlock")
   773  
   774  		fmt.Println("relock")
   775  		kvPair, err = lockMethod(key)
   776  		assert.NoError(t, err, "Failed to lock after unlock")
   777  
   778  		fmt.Println("reunlock")
   779  		err = kv.Unlock(kvPair)
   780  		assert.NoError(t, err, "Unexpected error from Unlock")
   781  
   782  		fmt.Println("repeat lock once")
   783  		kvPair, err = lockMethod(key)
   784  		assert.NoError(t, err, "Failed to lock unlock")
   785  
   786  		done := 0
   787  		go func() {
   788  			time.Sleep(time.Second * 10)
   789  			done = 1
   790  			err = kv.Unlock(kvPair)
   791  			fmt.Println("repeat lock unlock once")
   792  			assert.NoError(t, err, "Unexpected error from Unlock")
   793  		}()
   794  		fmt.Println("repeat lock lock twice")
   795  		kvPair, err = lockMethod(key)
   796  		assert.NoError(t, err, "Failed to lock")
   797  		assert.Equal(t, done, 1, "Locked before unlock")
   798  		if done != 1 {
   799  			logrus.Fatalf("Exiting because done != 1")
   800  		}
   801  		fmt.Println("repeat lock unlock twice")
   802  		err = kv.Unlock(kvPair)
   803  		assert.NoError(t, err, "Unexpected error from Unlock")
   804  
   805  		for done == 0 {
   806  			time.Sleep(time.Second)
   807  		}
   808  
   809  		key = "doubleLock"
   810  		kvPair, err = lockMethod(key)
   811  		assert.NoError(t, err, "Unexpected error in lock")
   812  		go func() {
   813  			time.Sleep(10 * time.Second)
   814  			err = kv.Unlock(kvPair)
   815  			assert.NoError(t, err, "Unexpected error from Unlock")
   816  		}()
   817  		kvPair2, err := lockMethod(key)
   818  		assert.NoError(t, err, "Double lock")
   819  		err = kv.Unlock(kvPair2)
   820  		assert.NoError(t, err, "Unexpected error from Unlock")
   821  
   822  		kvPair, err = lockMethod("key1")
   823  		assert.NoError(t, err, "Unexpected error in lock")
   824  		go func() {
   825  			time.Sleep(1 * time.Second)
   826  			err = kv.Unlock(kvPair)
   827  			assert.NoError(t, err, "Unexpected error from Unlock")
   828  		}()
   829  		kvPair2, err = lockMethod("key2")
   830  		assert.NoError(t, err, "diff lock")
   831  		err = kv.Unlock(kvPair2)
   832  		assert.NoError(t, err, "Unexpected error from Unlock")
   833  
   834  		lockTimedout := false
   835  		fatalLockCb := func(err error, format string, args ...interface{}) {
   836  			logrus.Infof("Lock timeout called: "+format, args...)
   837  			lockTimedout = true
   838  		}
   839  		kv.SetFatalCb(fatalLockCb)
   840  		kv.SetLockHoldDuration(5 * time.Second)
   841  		assert.Equal(t, kv.GetLockHoldDuration(), 5*time.Second, "get lock timeout")
   842  		kvPair2, err = lockMethod("key2")
   843  		time.Sleep(15 * time.Second)
   844  		assert.True(t, lockTimedout, "lock timeout not called")
   845  		err = kv.Unlock(kvPair2)
   846  		kv.SetLockHoldDuration(5 * time.Second)
   847  	}
   848  }
   849  
   850  func lockBetweenRestarts(kv kvdb.Kvdb, t *testing.T, start StartKvdb, stop StopKvdb) {
   851  	lockMethods := getLockMethods(kv)
   852  	for _, lockMethod := range lockMethods {
   853  		// Try to take the lock again
   854  		// We need this test for consul to check if LockDelay is not set
   855  		fmt.Println("lock before restarting kvdb")
   856  		kvPairBeforeRestart, err := lockMethod("key3")
   857  		assert.NoError(t, err, "Unable to take a lock")
   858  		fmt.Println("stopping kvdb")
   859  		err = stop()
   860  		assert.NoError(t, err, "Unable to stop kvdb")
   861  		// Unlock the key
   862  		go func() { kv.Unlock(kvPairBeforeRestart) }()
   863  
   864  		time.Sleep(30 * time.Second)
   865  
   866  		fmt.Println("starting kvdb")
   867  		err = start(false)
   868  		assert.NoError(t, err, "Unable to start kvdb")
   869  		time.Sleep(40 * time.Second)
   870  
   871  		lockChan := make(chan int)
   872  		var kvPair3 *kvdb.KVPair
   873  		go func() {
   874  			kvPair3, err = lockMethod("key3")
   875  			lockChan <- 1
   876  		}()
   877  		select {
   878  		case <-time.After(20 * time.Second):
   879  			assert.Fail(t, "Unable to take a lock whose session is expired")
   880  		case <-lockChan:
   881  		}
   882  		err = kv.Unlock(kvPair3)
   883  		assert.NoError(t, err, "unable to unlock")
   884  	}
   885  }
   886  
   887  func getTimeoutLock(kv kvdb.Kvdb, key string, lockerID string, tryDuration time.Duration, holdDuration time.Duration, kvChan chan *kvdb.KVPair, errChan chan error) {
   888  	kvPair, err := kv.LockWithTimeout(key, lockerID, tryDuration, holdDuration)
   889  	kvChan <- kvPair
   890  	errChan <- err
   891  }
   892  
   893  func lockTimeoutError(kv kvdb.Kvdb, t *testing.T) {
   894  	fmt.Println("lockTimeoutError() started")
   895  
   896  	kvChan := make(chan *kvdb.KVPair)
   897  	errChan := make(chan error)
   898  	key := "timeoutLockTest"
   899  	holdDuration := 30 * time.Second
   900  	tryDuration := 5 * time.Second
   901  	go getTimeoutLock(kv, key, "timeouttest1", tryDuration, holdDuration, kvChan, errChan)
   902  	time.Sleep(2 * time.Second)
   903  	go getTimeoutLock(kv, key, "timeouttest2", tryDuration, holdDuration, kvChan, errChan)
   904  	kvPair1, kvPair2 := <-kvChan, <-kvChan
   905  	err1, err2 := <-errChan, <-errChan
   906  	assert.NotNil(t, kvPair1, "Problem in acquiring Lock")
   907  	assert.Nil(t, kvPair2, "Lock acquired incorrectly")
   908  	assert.NoError(t, err1, "Unexpected error while trying to acquire lock")
   909  	assert.Error(t, err2, "Unexpected behaviour")
   910  
   911  	err := kv.Unlock(kvPair1)
   912  	assert.NoError(t, err, "Unexpected error while unlock")
   913  	go getTimeoutLock(kv, key, "timeouttest3", tryDuration, holdDuration, kvChan, errChan)
   914  	kvPair2 = <-kvChan
   915  	assert.NotNil(t, kvPair2, "Problem in acquiring Lock after Unlock")
   916  
   917  	fmt.Println("lockTimeoutError() ended successfully")
   918  }
   919  
   920  func lockBasic(kv kvdb.Kvdb, t *testing.T) {
   921  	lockMethods := getLockMethods(kv)
   922  
   923  	for _, lockMethod := range lockMethods {
   924  		fmt.Println("lock")
   925  
   926  		key := "locktest"
   927  		kvPair, err := lockMethod(key)
   928  		assert.NoError(t, err, "Unexpected error in lock")
   929  
   930  		if kvPair == nil {
   931  			return
   932  		}
   933  
   934  		err = kv.Unlock(kvPair)
   935  		assert.NoError(t, err, "Unexpected error from Unlock")
   936  
   937  		kvPair, err = lockMethod(key)
   938  		assert.NoError(t, err, "Failed to lock after unlock")
   939  
   940  		err = kv.Unlock(kvPair)
   941  		assert.NoError(t, err, "Unexpected error from Unlock")
   942  	}
   943  
   944  	// lock with timeout
   945  	key := "testTimeoutKey"
   946  	holdDuration := 30 * time.Second
   947  	tryDuration := 5 * time.Second
   948  	kvPair, err := kv.LockWithTimeout(key, "test", tryDuration, holdDuration)
   949  	assert.NoError(t, err, "Unexpected error in lock")
   950  
   951  	tryStart := time.Now()
   952  	_, err = kv.LockWithTimeout(key, "test", tryDuration, holdDuration)
   953  	if err == nil {
   954  		logrus.Fatalf("Exiting because expected error %v %v", tryDuration, holdDuration)
   955  	}
   956  	duration := time.Since(tryStart)
   957  	assert.True(t, duration < tryDuration+time.Second, "try duration")
   958  	assert.Error(t, err, "lock expired before timeout")
   959  
   960  	time.Sleep(holdDuration - time.Since(tryStart) - 5*time.Second)
   961  
   962  	_, err = kv.LockWithTimeout(key, "test", 1*time.Second, holdDuration)
   963  	duration = time.Since(tryStart)
   964  	assert.Error(t, err, "lock expired before timeout")
   965  
   966  	err = kv.Unlock(kvPair)
   967  	assert.NoError(t, err, "Unexpected error from Unlock")
   968  	fmt.Println("Ending lock basic")
   969  }
   970  
   971  func watchFn(
   972  	prefix string,
   973  	opaque interface{},
   974  	kvp *kvdb.KVPair,
   975  	err error,
   976  ) error {
   977  	data := opaque.(*watchData)
   978  	time.Sleep(100 * time.Millisecond)
   979  	if err != nil {
   980  		assert.Equal(data.t, err, kvdb.ErrWatchStopped)
   981  		data.watchStopped = true
   982  		return err
   983  
   984  	}
   985  	fmt.Printf("+")
   986  
   987  	// Doesn't work for ETCD because HTTP header contains Etcd-Index
   988  	/*
   989  		assert.True(data.t, kvp.KVDBIndex >= data.updateIndex,
   990  			"KVDBIndex %v must be >= than updateIndex %v",
   991  			kvp.KVDBIndex, data.updateIndex)
   992  
   993  		assert.True(data.t, kvp.KVDBIndex > data.localIndex,
   994  			"For Key (%v) : KVDBIndex %v must be > than localIndex %v action %v %v",
   995  			kvp.Key, kvp.KVDBIndex, data.localIndex, kvp.Action, kvdb.KVCreate)
   996  	*/
   997  
   998  	assert.True(data.t, kvp.ModifiedIndex > data.localIndex,
   999  		"For Key (%v) : ModifiedIndex %v must be > than localIndex %v",
  1000  		kvp.Key, kvp.ModifiedIndex, data.localIndex)
  1001  
  1002  	data.localIndex = kvp.ModifiedIndex
  1003  
  1004  	if data.whichKey == 0 {
  1005  		assert.Contains(data.t, data.otherKey, kvp.Key,
  1006  			"Bad kvpair key %s expecting %s with action %v",
  1007  			kvp.Key, data.key, kvp.Action)
  1008  	} else {
  1009  		assert.Contains(data.t, data.key, kvp.Key,
  1010  			"Bad kvpair key %s expecting %s with action %v",
  1011  			kvp.Key, data.key, kvp.Action)
  1012  	}
  1013  
  1014  	assert.Equal(data.t, data.action, kvp.Action,
  1015  		"For Key (%v) : Expected action %v actual %v",
  1016  		kvp.Key, data.action, kvp.Action)
  1017  	if data.action != kvp.Action {
  1018  		value := string(kvp.Value)
  1019  		logrus.Panicf("Aborting because (%v != %v) (%v) %v != %v (Value = %v)",
  1020  			data.action, kvp.Action, prefix, data, kvp, value)
  1021  	}
  1022  
  1023  	if string(kvp.Value) == data.stop {
  1024  		return errors.New(data.stop)
  1025  	}
  1026  
  1027  	atomic.AddInt32(&data.reader, 1)
  1028  	return nil
  1029  }
  1030  
  1031  func watchUpdate(kv kvdb.Kvdb, data *watchData) error {
  1032  	var err error
  1033  	var kvp *kvdb.KVPair
  1034  
  1035  	data.reader, data.writer = 0, 0
  1036  	atomic.AddInt32(&data.writer, 1)
  1037  	// whichKey = 1 : key
  1038  	// whichKey = 0 : otherKey
  1039  	atomic.SwapInt32(&data.whichKey, 1)
  1040  	data.action = kvdb.KVCreate
  1041  	fmt.Printf("-")
  1042  	fmt.Printf("XXX Creating watchUpdate key %v\n", data.key)
  1043  	kvp, err = kv.Create(data.key, []byte("bar"), 0)
  1044  	for i := 0; i < data.iterations && err == nil; i++ {
  1045  		fmt.Printf("-")
  1046  
  1047  		for data.writer != data.reader {
  1048  			time.Sleep(time.Millisecond * 100)
  1049  		}
  1050  		atomic.AddInt32(&data.writer, 1)
  1051  		data.action = kvdb.KVSet
  1052  		fmt.Printf("XXX Putting watchUpdate key %v\n", data.key)
  1053  		kvp, err = kv.Put(data.key, []byte("bar"), 0)
  1054  
  1055  		data.updateIndex = kvp.KVDBIndex
  1056  		assert.NoError(data.t, err, "Unexpected error in Put")
  1057  	}
  1058  
  1059  	fmt.Printf("-")
  1060  	for data.writer != data.reader {
  1061  		time.Sleep(time.Millisecond * 100)
  1062  	}
  1063  	atomic.AddInt32(&data.writer, 1)
  1064  	// Delete key
  1065  	data.action = kvdb.KVDelete
  1066  	kv.Delete(data.key)
  1067  
  1068  	fmt.Printf("-")
  1069  	for data.writer != data.reader {
  1070  		time.Sleep(time.Millisecond * 100)
  1071  	}
  1072  	atomic.AddInt32(&data.writer, 1)
  1073  
  1074  	atomic.SwapInt32(&data.whichKey, 0)
  1075  	data.action = kvdb.KVDelete
  1076  	// Delete otherKey
  1077  	kv.Delete(data.otherKey)
  1078  
  1079  	fmt.Printf("-")
  1080  	for data.writer != data.reader {
  1081  		time.Sleep(time.Millisecond * 100)
  1082  	}
  1083  	atomic.AddInt32(&data.writer, 1)
  1084  
  1085  	atomic.SwapInt32(&data.whichKey, 1)
  1086  	data.action = kvdb.KVCreate
  1087  	_, err = kv.Create(data.key, []byte(data.stop), 0)
  1088  	return err
  1089  }
  1090  
  1091  func watchKey(kv kvdb.Kvdb, t *testing.T) {
  1092  	fmt.Println("\nwatchKey")
  1093  
  1094  	watchData := watchData{
  1095  		t:          t,
  1096  		key:        "tree/key1",
  1097  		otherKey:   "tree/otherKey1",
  1098  		stop:       "stop",
  1099  		iterations: 2,
  1100  	}
  1101  
  1102  	kv.Delete(watchData.key)
  1103  	kv.Delete(watchData.otherKey)
  1104  	// First create a key. We should not get update for this create.
  1105  	kvp, err := kv.Create(watchData.otherKey, []byte("bar"), 0)
  1106  	// Let the create operation finish and then start the watch
  1107  	time.Sleep(2 * time.Second)
  1108  
  1109  	err = kv.WatchKey(watchData.otherKey, kvp.ModifiedIndex, &watchData, watchFn)
  1110  	if err != nil {
  1111  		fmt.Printf("Cannot test watchKey: %v\n", err)
  1112  		return
  1113  	}
  1114  
  1115  	err = kv.WatchKey(watchData.key, 0, &watchData, watchFn)
  1116  	if err != nil {
  1117  		fmt.Printf("Cannot test watchKey: %v\n", err)
  1118  		return
  1119  	}
  1120  
  1121  	// Sleep for sometime before calling the watchUpdate go routine.
  1122  	time.Sleep(time.Second * 2)
  1123  
  1124  	go watchUpdate(kv, &watchData)
  1125  
  1126  	for watchData.watchStopped == false {
  1127  		time.Sleep(time.Millisecond * 100)
  1128  	}
  1129  
  1130  	// Stop the second watch
  1131  	atomic.SwapInt32(&watchData.whichKey, 0)
  1132  	watchData.action = kvdb.KVCreate
  1133  	_, err = kv.Create(watchData.otherKey, []byte(watchData.stop), 0)
  1134  }
  1135  
  1136  func randomUpdate(kv kvdb.Kvdb, w *watchData) {
  1137  	for w.watchStopped == false {
  1138  		kv.Put("randomKey", []byte("bar"), 0)
  1139  		time.Sleep(time.Millisecond * 80)
  1140  	}
  1141  }
  1142  
  1143  func watchTree(kv kvdb.Kvdb, t *testing.T) {
  1144  	fmt.Println("\nwatchTree")
  1145  
  1146  	tree := "tree"
  1147  
  1148  	watchData := watchData{
  1149  		t:          t,
  1150  		key:        tree + "/key",
  1151  		otherKey:   tree + "/otherKey",
  1152  		stop:       "stop",
  1153  		iterations: 2,
  1154  	}
  1155  	_, err := kv.Delete(watchData.key)
  1156  	_, err = kv.Delete(watchData.otherKey)
  1157  
  1158  	// First create a tree to watch for. We should not get update for this create.
  1159  	kvp, err := kv.Create(watchData.otherKey, []byte("bar"), 0)
  1160  	// Let the create operation finish and then start the watch
  1161  
  1162  	time.Sleep(time.Second)
  1163  	err = kv.WatchTree(tree, kvp.ModifiedIndex, &watchData, watchFn)
  1164  	if err != nil {
  1165  		fmt.Printf("Cannot test watchKey: %v\n", err)
  1166  		return
  1167  	}
  1168  
  1169  	// Sleep for sometime before calling the watchUpdate go routine.
  1170  	time.Sleep(time.Millisecond * 100)
  1171  
  1172  	go randomUpdate(kv, &watchData)
  1173  	go watchUpdate(kv, &watchData)
  1174  
  1175  	for watchData.watchStopped == false {
  1176  		time.Sleep(time.Millisecond * 100)
  1177  	}
  1178  }
  1179  
  1180  func watchWithIndexCb(
  1181  	prefix string,
  1182  	opaque interface{},
  1183  	kvp *kvdb.KVPair,
  1184  	err error,
  1185  ) error {
  1186  
  1187  	data, ok := opaque.(*watchData)
  1188  	if !ok {
  1189  		data.t.Fatalf("Unable to parse waitIndex in watch callback")
  1190  	}
  1191  	if err != nil {
  1192  		assert.Equal(data.t, err, kvdb.ErrWatchStopped)
  1193  		data.watchStopped = true
  1194  		return err
  1195  
  1196  	}
  1197  	if kvp != nil && len(kvp.Value) != 0 && string(kvp.Value) == "stop" {
  1198  		// Stop the watch
  1199  		return fmt.Errorf("stop the watch")
  1200  	}
  1201  	assert.True(data.t, kvp.ModifiedIndex >= data.localIndex,
  1202  		"For key: %v. ModifiedIndex (%v) should be > than waitIndex (%v)",
  1203  		kvp.Key, kvp.ModifiedIndex, data.localIndex,
  1204  	)
  1205  	assert.True(data.t, kvp.ModifiedIndex <= data.localIndex+3,
  1206  		"For key: %v. Got extra updates. Current ModifiedIndex: %v. Expected last update index: %v",
  1207  		kvp.Key, kvp.ModifiedIndex, data.localIndex+2,
  1208  	)
  1209  	if kvp.ModifiedIndex == data.localIndex+3 {
  1210  		assert.True(data.t, kvp.Action == kvdb.KVDelete,
  1211  			"Expected action: %v, action action: %v",
  1212  			kvdb.KVDelete, kvp.Action,
  1213  		)
  1214  	}
  1215  	return nil
  1216  }
  1217  
  1218  func watchWithIndex(kv kvdb.Kvdb, t *testing.T) {
  1219  	fmt.Println("\nwatchWithIndex")
  1220  
  1221  	tree := "indexTree"
  1222  	subtree := tree + "/subtree"
  1223  	key := subtree + "/watchWithIndex"
  1224  	key1 := subtree + "/watchWithIndex21"
  1225  
  1226  	kv.DeleteTree(tree)
  1227  
  1228  	kvp, err := kv.Create(key, []byte("bar"), 0)
  1229  	assert.NoError(t, err, "Unexpected error in create: %v", err)
  1230  
  1231  	time.Sleep(time.Millisecond * 100)
  1232  
  1233  	waitIndex := kvp.ModifiedIndex + 2
  1234  	watchData := watchData{
  1235  		t:          t,
  1236  		key:        key,
  1237  		localIndex: waitIndex,
  1238  	}
  1239  
  1240  	err = kv.WatchTree(tree, waitIndex, &watchData, watchWithIndexCb)
  1241  	if err != nil {
  1242  		fmt.Printf("Cannot test watchTree for watchWithIndex: %v", err)
  1243  		return
  1244  	}
  1245  	// Should not get updates for these
  1246  	kv.Put(key, []byte("bar1"), 0)
  1247  	kv.Put(key, []byte("bar1"), 0)
  1248  	// Should get updates for these
  1249  	kv.Put(key, []byte("bar2"), 0)
  1250  	kv.Create(key1, []byte("bar"), 0)
  1251  	kv.Delete(key)
  1252  	kv.Put(key, []byte("stop"), 0)
  1253  }
  1254  
  1255  func cas(kv kvdb.Kvdb, t *testing.T) {
  1256  	fmt.Println("cas")
  1257  
  1258  	key := "foo/docker"
  1259  	val := "great"
  1260  	defer func() {
  1261  		kv.DeleteTree(key)
  1262  	}()
  1263  
  1264  	kvPair, err := kv.Put(key, []byte(val), 0)
  1265  	assert.NoError(t, err, "Unxpected error in Put")
  1266  
  1267  	kvPair, err = kv.Get(key)
  1268  	assert.NoError(t, err, "Failed in Get")
  1269  
  1270  	_, err = kv.CompareAndSet(kvPair, kvdb.KVFlags(0), []byte("badval"))
  1271  	assert.Error(t, err, "CompareAndSet should fail on an incorrect previous value")
  1272  
  1273  	copyKVPair := *kvPair
  1274  	copyKVPair.ModifiedIndex++
  1275  	_, err = kv.CompareAndSet(&copyKVPair, kvdb.KVModifiedIndex, nil)
  1276  	assert.Error(t, err, "CompareAndSet should fail on an incorrect modified index")
  1277  
  1278  	//kvPair.ModifiedIndex--
  1279  	copyKVPair.ModifiedIndex--
  1280  	kvPair, err = kv.CompareAndSet(&copyKVPair, kvdb.KVModifiedIndex, nil)
  1281  	assert.NoError(t, err, "CompareAndSet should succeed on an correct modified index")
  1282  
  1283  	kvPairNew, err := kv.CompareAndSet(kvPair, kvdb.KVFlags(0), []byte(val))
  1284  	assert.NoError(t, err, "CompareAndSet should succeed on an correct value")
  1285  
  1286  	if kvPairNew != nil {
  1287  		kvPair = kvPairNew
  1288  	}
  1289  
  1290  	kvPair, err = kv.CompareAndSet(kvPair, kvdb.KVModifiedIndex, []byte(val))
  1291  	assert.NoError(t, err, "CompareAndSet should succeed on an correct value and modified index")
  1292  }
  1293  
  1294  func cad(kv kvdb.Kvdb, t *testing.T) {
  1295  	fmt.Println("cad")
  1296  
  1297  	key := "foo/docker"
  1298  	val := "great"
  1299  	defer func() {
  1300  		kv.DeleteTree(key)
  1301  	}()
  1302  
  1303  	kvPair, err := kv.Put(key, []byte(val), 0)
  1304  	assert.NoError(t, err, "Unxpected error in Put")
  1305  
  1306  	kvPair, err = kv.Get(key)
  1307  	assert.NoError(t, err, "Failed in Get")
  1308  
  1309  	copyKVPair1 := *kvPair
  1310  	copyKVPair1.Value = []byte("badval")
  1311  	_, err = kv.CompareAndDelete(&copyKVPair1, kvdb.KVFlags(0))
  1312  	assert.Error(t, err, "CompareAndDelete should fail on an incorrect previous value")
  1313  
  1314  	copyKVPair2 := *kvPair
  1315  	copyKVPair2.ModifiedIndex++
  1316  	_, err = kv.CompareAndDelete(&copyKVPair2, kvdb.KVModifiedIndex)
  1317  	assert.Error(t, err, "CompareAndDelete should fail on an incorrect modified index")
  1318  
  1319  	//kvPair.ModifiedIndex--
  1320  	copyKVPair2.ModifiedIndex--
  1321  	kvPair, err = kv.CompareAndDelete(&copyKVPair2, kvdb.KVModifiedIndex)
  1322  	assert.NoError(t, err, "CompareAndDelete should succeed on an correct modified index")
  1323  
  1324  	kvPair, err = kv.Put(key, []byte(val), 0)
  1325  	assert.NoError(t, err, "Unxpected error in Put")
  1326  
  1327  	_, err = kv.CompareAndDelete(kvPair, kvdb.KVFlags(0))
  1328  	assert.NoError(t, err, "CompareAndDelete should succeed on an correct value")
  1329  }
  1330  
  1331  func addUser(kv kvdb.Kvdb, t *testing.T) {
  1332  	fmt.Println("addUser")
  1333  
  1334  	err := kv.AddUser("test", "test123")
  1335  	assert.NoError(t, err, "Error in Adding User")
  1336  }
  1337  
  1338  func removeUser(kv kvdb.Kvdb, t *testing.T) {
  1339  	fmt.Println("removeUser")
  1340  
  1341  	err := kv.RemoveUser("test")
  1342  	assert.NoError(t, err, "Error in Removing User")
  1343  }
  1344  
  1345  func grantRevokeUser(kvRootUser kvdb.Kvdb, datastoreInit kvdb.DatastoreInit, t *testing.T) {
  1346  	fmt.Println("grantRevokeUser")
  1347  
  1348  	kvRootUser.Create("allow1/foo", []byte("bar"), 0)
  1349  	kvRootUser.Create("allow2/foo", []byte("bar"), 0)
  1350  	kvRootUser.Create("disallow/foo", []byte("bar"), 0)
  1351  	err := kvRootUser.GrantUserAccess("test", kvdb.ReadWritePermission, "allow1/*")
  1352  	assert.NoError(t, err, "Error in Grant User")
  1353  	err = kvRootUser.GrantUserAccess("test", kvdb.ReadWritePermission, "allow2/*")
  1354  	assert.NoError(t, err, "Error in Grant User")
  1355  	err = kvRootUser.GrantUserAccess("test", kvdb.ReadWritePermission, "disallow/*")
  1356  	assert.NoError(t, err, "Error in Grant User")
  1357  	err = kvRootUser.RevokeUsersAccess("test", kvdb.ReadWritePermission, "disallow/*")
  1358  	assert.NoError(t, err, "Error in Revoke User")
  1359  
  1360  	options := make(map[string]string)
  1361  	options[kvdb.UsernameKey] = "test"
  1362  	options[kvdb.PasswordKey] = "test123"
  1363  	options[kvdb.CAFileKey] = "/etc/pwx/pwx-ca.crt"
  1364  	options[kvdb.CertFileKey] = "/etc/pwx/pwx-user-cert.crt"
  1365  	options[kvdb.CertKeyFileKey] = "/etc/pwx/pwx-user-key.key"
  1366  	machines := []string{"https://192.168.56.101:2379"}
  1367  	kvTestUser, _ := datastoreInit("pwx/test", machines, options, fatalErrorCb())
  1368  
  1369  	actual := "actual"
  1370  	_, err = kvTestUser.Put("allow1/foo", []byte(actual), 0)
  1371  	assert.NoError(t, err, "Error in writing to allowed tree")
  1372  	kvPair, err := kvTestUser.Get("allow1/foo")
  1373  	assert.NoError(t, err, "Error in accessing allowed values")
  1374  	if err == nil {
  1375  		assert.Equal(t, string(kvPair.Value), "actual")
  1376  	}
  1377  
  1378  	_, err = kvTestUser.Put("allow2/foo", []byte(actual), 0)
  1379  	assert.NoError(t, err, "Error in writing to allowed tree")
  1380  	kvPair, err = kvTestUser.Get("allow2/foo")
  1381  	assert.NoError(t, err, "Error in accessing allowed values")
  1382  	if err == nil {
  1383  		assert.Equal(t, string(kvPair.Value), "actual")
  1384  	}
  1385  
  1386  	actual2 := "actual2"
  1387  	_, err = kvTestUser.Put("disallow/foo", []byte(actual2), 0)
  1388  	assert.Error(t, err, "Expected error in writing to disallowed tree")
  1389  	kvPair, err = kvTestUser.Get("disallow/foo")
  1390  	assert.Error(t, err, "Expected error in accessing disallowed values")
  1391  
  1392  	kvRootUser.DeleteTree("allow1")
  1393  	kvRootUser.DeleteTree("allow2")
  1394  	kvRootUser.DeleteTree("disallow")
  1395  }
  1396  
  1397  func collect(kv kvdb.Kvdb, t *testing.T) {
  1398  	for _, useStartVersion := range []bool{false, true} {
  1399  
  1400  		startVersion := func(modifiedVersion uint64) uint64 {
  1401  			if useStartVersion {
  1402  				return modifiedVersion
  1403  			}
  1404  			return 0
  1405  		}
  1406  
  1407  		fmt.Println("collect")
  1408  
  1409  		// XXX FIXME this is a bug... root should not have the prefix
  1410  		root := "pwx/test/collect"
  1411  		firstLevel := root + "/first"
  1412  		secondLevel := root + "/second"
  1413  
  1414  		kv.DeleteTree(root)
  1415  
  1416  		kvp, _ := kv.Create(firstLevel, []byte("bar"), 0)
  1417  		fmt.Printf("KVP is %v and KV is %v\n", kvp, kv)
  1418  		collector, _ := kvdb.NewUpdatesCollector(kv, secondLevel,
  1419  			startVersion(kvp.CreatedIndex))
  1420  		time.Sleep(time.Second)
  1421  		var updates []*kvdb.KVPair
  1422  		updateFn := func(start, end int) uint64 {
  1423  			lastUpdateVersion := uint64(0)
  1424  			for i := start; i < end; i++ {
  1425  				newLeaf := strconv.Itoa(i)
  1426  				// First update the tree being watched.
  1427  				kvp1, _ := kv.Create(secondLevel+"/"+newLeaf, []byte(newLeaf), 0)
  1428  				// Next update another value in kvdb which is not being
  1429  				// watched, this update will cause kvdb index to move forward.
  1430  				kv.Update(firstLevel, []byte(newLeaf), 0)
  1431  				updates = append(updates, kvp1)
  1432  				lastUpdateVersion = kvp1.ModifiedIndex
  1433  			}
  1434  			return lastUpdateVersion
  1435  		}
  1436  		lastUpdateVersion := updateFn(0, 10)
  1437  		// Allow watch updates to come back.
  1438  		time.Sleep(time.Millisecond * 500)
  1439  		collector.Stop()
  1440  
  1441  		updateFn(10, 20)
  1442  		lastKVIndex := kvp.CreatedIndex
  1443  		lastLeafIndex := -1
  1444  		cb := func(prefix string, opaque interface{}, kvp *kvdb.KVPair,
  1445  			err error) error {
  1446  			fmt.Printf("\nReplaying KVP: %v", *kvp)
  1447  			assert.True(t, err == nil, "Error is nil %v", err)
  1448  			assert.True(t, kvp.ModifiedIndex > lastKVIndex,
  1449  				"Modified index %v lower than last index %v",
  1450  				kvp.ModifiedIndex, lastKVIndex)
  1451  			lastKVIndex = kvp.ModifiedIndex
  1452  			strValue := string(kvp.Value)
  1453  			value := secondLevel + "/" + strValue
  1454  			assert.True(t, strings.Compare(kvp.Key, value) == 0,
  1455  				"Key: %v, Value: %v", kvp.Key, value)
  1456  			leafIndex, _ := strconv.Atoi(strValue)
  1457  			assert.True(t, leafIndex == lastLeafIndex+1,
  1458  				"Last leaf: %v, leaf: %v", kvp.Key,
  1459  				value)
  1460  			lastLeafIndex = leafIndex
  1461  			return nil
  1462  		}
  1463  
  1464  		replayCb := make([]kvdb.ReplayCb, 1)
  1465  		replayCb[0].Prefix = secondLevel
  1466  		replayCb[0].WatchCB = cb
  1467  		replayCb[0].WaitIndex = kvp.CreatedIndex
  1468  
  1469  		lastVersion, err := collector.ReplayUpdates(replayCb)
  1470  		assert.True(t, err == nil, "Replay encountered error %v", err)
  1471  		assert.True(t, lastLeafIndex == 9, "Last leaf index %v, expected : 9",
  1472  			lastLeafIndex)
  1473  		assert.True(t, lastVersion == lastUpdateVersion,
  1474  			"Last update %d and last replay %d version mismatch",
  1475  			lastVersion, lastUpdateVersion)
  1476  
  1477  		// Test with no updates.
  1478  		thirdLevel := root + "/third"
  1479  		kvp, _ = kv.Create(thirdLevel, []byte("bar_update"), 0)
  1480  		collector, _ = kvdb.NewUpdatesCollector(kv, thirdLevel,
  1481  			startVersion(kvp.ModifiedIndex))
  1482  		time.Sleep(2 * time.Second)
  1483  		replayCb[0].WaitIndex = kvp.ModifiedIndex
  1484  		_, err = collector.ReplayUpdates(replayCb)
  1485  		assert.True(t, err == nil, "Replay encountered error %v", err)
  1486  		assert.True(t, lastLeafIndex == 9, "Last leaf index %v, expected : 9",
  1487  			lastLeafIndex)
  1488  		if lastLeafIndex != 9 {
  1489  			logrus.Fatalf("lastLeafIndex is %v", lastLeafIndex)
  1490  		}
  1491  
  1492  		// Test with kvdb returning error because update index was too old.
  1493  		fourthLevel := root + "/fourth"
  1494  		kv.Create(fourthLevel, []byte(strconv.Itoa(0)), 0)
  1495  		for i := 1; i < 2000; i++ {
  1496  			kv.Update(fourthLevel, []byte(strconv.Itoa(i)), 0)
  1497  		}
  1498  		collector, _ = kvdb.NewUpdatesCollector(kv, fourthLevel,
  1499  			startVersion(kvp.ModifiedIndex))
  1500  		kv.Update(fourthLevel, []byte(strconv.Itoa(2000)), 0)
  1501  		time.Sleep(500 * time.Millisecond)
  1502  		cb = func(prefix string, opaque interface{}, kvp *kvdb.KVPair,
  1503  			err error) error {
  1504  			fmt.Printf("Error is %v", err)
  1505  			assert.True(t, err != nil, "Error is nil %v", err)
  1506  			return nil
  1507  		}
  1508  		replayCb[0].WatchCB = cb
  1509  		replayCb[0].WaitIndex = kvp.ModifiedIndex
  1510  		collector.ReplayUpdates(replayCb)
  1511  	}
  1512  }
  1513  
  1514  func serialization(kv kvdb.Kvdb, t *testing.T) {
  1515  	fmt.Println("serialization")
  1516  	kv.DeleteTree("")
  1517  	prefix := "/folder"
  1518  	type A struct {
  1519  		A1 int
  1520  		A2 string
  1521  	}
  1522  	type B struct {
  1523  		B1 string
  1524  	}
  1525  	a1 := A{1, "a"}
  1526  	b1 := B{"2"}
  1527  	c1 := A{2, "b"}
  1528  	_, err := kv.Put(prefix+"/a/a1", a1, 0)
  1529  	assert.NoError(t, err, "Unexpected error on put")
  1530  	_, err = kv.Put(prefix+"/b/b1", b1, 0)
  1531  	assert.NoError(t, err, "Unexpected error on put")
  1532  	_, err = kv.Put(prefix+"/c/c1", c1, 0)
  1533  	assert.NoError(t, err, "Unexpected error on put")
  1534  	kv.Delete(prefix + "/c/c1")
  1535  	b, err := kv.Serialize()
  1536  	assert.NoError(t, err, "Unexpected error on serialize")
  1537  	kvps, err := kv.Deserialize(b)
  1538  	assert.NoError(t, err, "Unexpected error on de-serialize")
  1539  	for _, kvp := range kvps {
  1540  		if strings.Contains(kvp.Key, "/a/a1") {
  1541  			aa := A{}
  1542  			err = json.Unmarshal(kvp.Value, &aa)
  1543  			assert.NoError(t, err, "Unexpected error on unmarshal")
  1544  			assert.Equal(t, aa.A1, a1.A1, "Unequal A values")
  1545  			assert.Equal(t, aa.A2, a1.A2, "Unequal A values")
  1546  		} else if strings.Contains(kvp.Key, "/b/b1") {
  1547  			bb := B{}
  1548  			err = json.Unmarshal(kvp.Value, &bb)
  1549  			assert.NoError(t, err, "Unexpected error on unmarshal")
  1550  			assert.Equal(t, bb.B1, b1.B1, "Unequal B values")
  1551  		} else if strings.Contains(kvp.Key, "/c") {
  1552  			// ETCD v2 will return an empty folder, but v3 and consul will not
  1553  			assert.Equal(t, len(kvp.Value), 0, "Unexpected C values")
  1554  		} else {
  1555  			t.Fatalf("Unexpected values returned by deserialize: %v", kvp.Key)
  1556  		}
  1557  	}
  1558  }
  1559  
  1560  func noQuorum(kv kvdb.Kvdb, t *testing.T) {
  1561  	key := "key"
  1562  	value := "value"
  1563  	sep := "/"
  1564  	ttl := uint64(0)
  1565  
  1566  	assert.True(t, len(kv.String()) > 0, "Unexpected error in String")
  1567  
  1568  	_, err := kv.Create(key, value, ttl)
  1569  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Create")
  1570  	_, err = kv.Get(key)
  1571  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Get")
  1572  	_, err = kv.Put(key, value, ttl)
  1573  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Put")
  1574  	_, _, err = kv.Snapshot(nil, true)
  1575  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Snapshot")
  1576  	_, err = kv.GetVal(key, value)
  1577  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in GetVal")
  1578  	_, err = kv.Update(key, value, ttl)
  1579  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Update")
  1580  	_, err = kv.Enumerate(key)
  1581  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Enumerate")
  1582  	_, err = kv.Keys(key, sep)
  1583  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Keys")
  1584  
  1585  	kvp := &kvdb.KVPair{Key: key, Value: []byte(value)}
  1586  	_, err = kv.CompareAndSet(kvp, 0, []byte(value))
  1587  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in CompareAndSet")
  1588  
  1589  	_, err = kv.Lock(key)
  1590  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Lock")
  1591  	_, err = kv.LockWithID(key, key)
  1592  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in LockWithID")
  1593  	_, err = kv.LockWithTimeout(key, key, time.Minute, time.Minute)
  1594  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in LockWithTimeout")
  1595  
  1596  	selectFn := func(val interface{}) bool {
  1597  		t.Fatal("select function called when no quorum exists")
  1598  		return false
  1599  	}
  1600  	copyFn := func(val interface{}) interface{} {
  1601  		t.Fatal("copy function called when no quorum exists")
  1602  		return val
  1603  	}
  1604  	_, err = kv.EnumerateWithSelect(key, selectFn, copyFn)
  1605  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in EnumerateWithSelect")
  1606  
  1607  	_, err = kv.SnapPut(nil)
  1608  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in SnapPut")
  1609  	err = kv.AddUser(key, value)
  1610  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in AddUser")
  1611  	err = kv.RemoveUser(key)
  1612  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in RemoveUser")
  1613  	_, err = kv.TxNew()
  1614  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in TxNew")
  1615  
  1616  	_, err = kv.Serialize()
  1617  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Serialize")
  1618  	_, err = kv.Deserialize([]byte{})
  1619  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Serialize")
  1620  
  1621  	_, err = kv.Delete(key)
  1622  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in Delete")
  1623  	err = kv.DeleteTree(key)
  1624  	assert.Error(t, err, kvdb.ErrNoQuorum, "error expected in DeleteTree")
  1625  
  1626  	// watch must return an error
  1627  	watchCb := func(prefix string, opaque interface{}, kvp *kvdb.KVPair, err error) error {
  1628  		assert.Error(t, err, "watch error expected")
  1629  		return err
  1630  	}
  1631  	kv.WatchKey(key, ttl, key, watchCb)
  1632  	kv.WatchTree(key, ttl, key, watchCb)
  1633  }