github.com/kjdelisle/consul@v1.4.5/api/kv_test.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"path"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  func TestAPI_ClientPutGetDelete(t *testing.T) {
    12  	t.Parallel()
    13  	c, s := makeClient(t)
    14  	defer s.Stop()
    15  
    16  	kv := c.KV()
    17  
    18  	// Get a get without a key
    19  	key := testKey()
    20  	pair, _, err := kv.Get(key, nil)
    21  	if err != nil {
    22  		t.Fatalf("err: %v", err)
    23  	}
    24  	if pair != nil {
    25  		t.Fatalf("unexpected value: %#v", pair)
    26  	}
    27  
    28  	value := []byte("test")
    29  
    30  	// Put a key that begins with a '/', this should fail
    31  	invalidKey := "/test"
    32  	p := &KVPair{Key: invalidKey, Flags: 42, Value: value}
    33  	if _, err := kv.Put(p, nil); err == nil {
    34  		t.Fatalf("Invalid key not detected: %s", invalidKey)
    35  	}
    36  
    37  	// Put the key
    38  	p = &KVPair{Key: key, Flags: 42, Value: value}
    39  	if _, err := kv.Put(p, nil); err != nil {
    40  		t.Fatalf("err: %v", err)
    41  	}
    42  
    43  	// Get should work
    44  	pair, meta, err := kv.Get(key, nil)
    45  	if err != nil {
    46  		t.Fatalf("err: %v", err)
    47  	}
    48  	if pair == nil {
    49  		t.Fatalf("expected value: %#v", pair)
    50  	}
    51  	if !bytes.Equal(pair.Value, value) {
    52  		t.Fatalf("unexpected value: %#v", pair)
    53  	}
    54  	if pair.Flags != 42 {
    55  		t.Fatalf("unexpected value: %#v", pair)
    56  	}
    57  	if meta.LastIndex == 0 {
    58  		t.Fatalf("unexpected value: %#v", meta)
    59  	}
    60  
    61  	// Delete
    62  	if _, err := kv.Delete(key, nil); err != nil {
    63  		t.Fatalf("err: %v", err)
    64  	}
    65  
    66  	// Get should fail
    67  	pair, _, err = kv.Get(key, nil)
    68  	if err != nil {
    69  		t.Fatalf("err: %v", err)
    70  	}
    71  	if pair != nil {
    72  		t.Fatalf("unexpected value: %#v", pair)
    73  	}
    74  }
    75  
    76  func TestAPI_ClientList_DeleteRecurse(t *testing.T) {
    77  	t.Parallel()
    78  	c, s := makeClient(t)
    79  	defer s.Stop()
    80  
    81  	kv := c.KV()
    82  
    83  	// Generate some test keys
    84  	prefix := testKey()
    85  	var keys []string
    86  	for i := 0; i < 100; i++ {
    87  		keys = append(keys, path.Join(prefix, testKey()))
    88  	}
    89  
    90  	// Set values
    91  	value := []byte("test")
    92  	for _, key := range keys {
    93  		p := &KVPair{Key: key, Value: value}
    94  		if _, err := kv.Put(p, nil); err != nil {
    95  			t.Fatalf("err: %v", err)
    96  		}
    97  	}
    98  
    99  	// List the values
   100  	pairs, meta, err := kv.List(prefix, nil)
   101  	if err != nil {
   102  		t.Fatalf("err: %v", err)
   103  	}
   104  	if len(pairs) != len(keys) {
   105  		t.Fatalf("got %d keys", len(pairs))
   106  	}
   107  	for _, pair := range pairs {
   108  		if !bytes.Equal(pair.Value, value) {
   109  			t.Fatalf("unexpected value: %#v", pair)
   110  		}
   111  	}
   112  	if meta.LastIndex == 0 {
   113  		t.Fatalf("unexpected value: %#v", meta)
   114  	}
   115  
   116  	// Delete all
   117  	if _, err := kv.DeleteTree(prefix, nil); err != nil {
   118  		t.Fatalf("err: %v", err)
   119  	}
   120  
   121  	// List the values
   122  	pairs, _, err = kv.List(prefix, nil)
   123  	if err != nil {
   124  		t.Fatalf("err: %v", err)
   125  	}
   126  	if len(pairs) != 0 {
   127  		t.Fatalf("got %d keys", len(pairs))
   128  	}
   129  }
   130  
   131  func TestAPI_ClientDeleteCAS(t *testing.T) {
   132  	t.Parallel()
   133  	c, s := makeClient(t)
   134  	defer s.Stop()
   135  
   136  	kv := c.KV()
   137  
   138  	// Put the key
   139  	key := testKey()
   140  	value := []byte("test")
   141  	p := &KVPair{Key: key, Value: value}
   142  	if work, _, err := kv.CAS(p, nil); err != nil {
   143  		t.Fatalf("err: %v", err)
   144  	} else if !work {
   145  		t.Fatalf("CAS failure")
   146  	}
   147  
   148  	// Get should work
   149  	pair, meta, err := kv.Get(key, nil)
   150  	if err != nil {
   151  		t.Fatalf("err: %v", err)
   152  	}
   153  	if pair == nil {
   154  		t.Fatalf("expected value: %#v", pair)
   155  	}
   156  	if meta.LastIndex == 0 {
   157  		t.Fatalf("unexpected value: %#v", meta)
   158  	}
   159  
   160  	// CAS update with bad index
   161  	p.ModifyIndex = 1
   162  	if work, _, err := kv.DeleteCAS(p, nil); err != nil {
   163  		t.Fatalf("err: %v", err)
   164  	} else if work {
   165  		t.Fatalf("unexpected CAS")
   166  	}
   167  
   168  	// CAS update with valid index
   169  	p.ModifyIndex = meta.LastIndex
   170  	if work, _, err := kv.DeleteCAS(p, nil); err != nil {
   171  		t.Fatalf("err: %v", err)
   172  	} else if !work {
   173  		t.Fatalf("unexpected CAS failure")
   174  	}
   175  }
   176  
   177  func TestAPI_ClientCAS(t *testing.T) {
   178  	t.Parallel()
   179  	c, s := makeClient(t)
   180  	defer s.Stop()
   181  
   182  	kv := c.KV()
   183  
   184  	// Put the key
   185  	key := testKey()
   186  	value := []byte("test")
   187  	p := &KVPair{Key: key, Value: value}
   188  	if work, _, err := kv.CAS(p, nil); err != nil {
   189  		t.Fatalf("err: %v", err)
   190  	} else if !work {
   191  		t.Fatalf("CAS failure")
   192  	}
   193  
   194  	// Get should work
   195  	pair, meta, err := kv.Get(key, nil)
   196  	if err != nil {
   197  		t.Fatalf("err: %v", err)
   198  	}
   199  	if pair == nil {
   200  		t.Fatalf("expected value: %#v", pair)
   201  	}
   202  	if meta.LastIndex == 0 {
   203  		t.Fatalf("unexpected value: %#v", meta)
   204  	}
   205  
   206  	// CAS update with bad index
   207  	newVal := []byte("foo")
   208  	p.Value = newVal
   209  	p.ModifyIndex = 1
   210  	if work, _, err := kv.CAS(p, nil); err != nil {
   211  		t.Fatalf("err: %v", err)
   212  	} else if work {
   213  		t.Fatalf("unexpected CAS")
   214  	}
   215  
   216  	// CAS update with valid index
   217  	p.ModifyIndex = meta.LastIndex
   218  	if work, _, err := kv.CAS(p, nil); err != nil {
   219  		t.Fatalf("err: %v", err)
   220  	} else if !work {
   221  		t.Fatalf("unexpected CAS failure")
   222  	}
   223  }
   224  
   225  func TestAPI_ClientWatchGet(t *testing.T) {
   226  	t.Parallel()
   227  	c, s := makeClient(t)
   228  	defer s.Stop()
   229  
   230  	kv := c.KV()
   231  
   232  	// Get a get without a key
   233  	key := testKey()
   234  	pair, meta, err := kv.Get(key, nil)
   235  	if err != nil {
   236  		t.Fatalf("err: %v", err)
   237  	}
   238  	if pair != nil {
   239  		t.Fatalf("unexpected value: %#v", pair)
   240  	}
   241  	if meta.LastIndex == 0 {
   242  		t.Fatalf("unexpected value: %#v", meta)
   243  	}
   244  
   245  	// Put the key
   246  	value := []byte("test")
   247  	doneCh := make(chan struct{})
   248  	go func() {
   249  		kv := c.KV()
   250  
   251  		time.Sleep(100 * time.Millisecond)
   252  		p := &KVPair{Key: key, Flags: 42, Value: value}
   253  		if _, err := kv.Put(p, nil); err != nil {
   254  			t.Fatalf("err: %v", err)
   255  		}
   256  		doneCh <- struct{}{}
   257  	}()
   258  
   259  	// Get should work
   260  	options := &QueryOptions{WaitIndex: meta.LastIndex}
   261  	pair, meta2, err := kv.Get(key, options)
   262  	if err != nil {
   263  		t.Fatalf("err: %v", err)
   264  	}
   265  	if pair == nil {
   266  		t.Fatalf("expected value: %#v", pair)
   267  	}
   268  	if !bytes.Equal(pair.Value, value) {
   269  		t.Fatalf("unexpected value: %#v", pair)
   270  	}
   271  	if pair.Flags != 42 {
   272  		t.Fatalf("unexpected value: %#v", pair)
   273  	}
   274  	if meta2.LastIndex <= meta.LastIndex {
   275  		t.Fatalf("unexpected value: %#v", meta2)
   276  	}
   277  
   278  	// Block until put finishes to avoid a race between it and deferred s.Stop()
   279  	<-doneCh
   280  }
   281  
   282  func TestAPI_ClientWatchList(t *testing.T) {
   283  	t.Parallel()
   284  	c, s := makeClient(t)
   285  	defer s.Stop()
   286  
   287  	kv := c.KV()
   288  
   289  	// Get a get without a key
   290  	prefix := testKey()
   291  	key := path.Join(prefix, testKey())
   292  	pairs, meta, err := kv.List(prefix, nil)
   293  	if err != nil {
   294  		t.Fatalf("err: %v", err)
   295  	}
   296  	if len(pairs) != 0 {
   297  		t.Fatalf("unexpected value: %#v", pairs)
   298  	}
   299  	if meta.LastIndex == 0 {
   300  		t.Fatalf("unexpected value: %#v", meta)
   301  	}
   302  
   303  	// Put the key
   304  	value := []byte("test")
   305  	doneCh := make(chan struct{})
   306  	go func() {
   307  		kv := c.KV()
   308  
   309  		time.Sleep(100 * time.Millisecond)
   310  		p := &KVPair{Key: key, Flags: 42, Value: value}
   311  		if _, err := kv.Put(p, nil); err != nil {
   312  			t.Fatalf("err: %v", err)
   313  		}
   314  		doneCh <- struct{}{}
   315  	}()
   316  
   317  	// Get should work
   318  	options := &QueryOptions{WaitIndex: meta.LastIndex}
   319  	pairs, meta2, err := kv.List(prefix, options)
   320  	if err != nil {
   321  		t.Fatalf("err: %v", err)
   322  	}
   323  	if len(pairs) != 1 {
   324  		t.Fatalf("expected value: %#v", pairs)
   325  	}
   326  	if !bytes.Equal(pairs[0].Value, value) {
   327  		t.Fatalf("unexpected value: %#v", pairs)
   328  	}
   329  	if pairs[0].Flags != 42 {
   330  		t.Fatalf("unexpected value: %#v", pairs)
   331  	}
   332  	if meta2.LastIndex <= meta.LastIndex {
   333  		t.Fatalf("unexpected value: %#v", meta2)
   334  	}
   335  
   336  	// Block until put finishes to avoid a race between it and deferred s.Stop()
   337  	<-doneCh
   338  }
   339  
   340  func TestAPI_ClientKeys_DeleteRecurse(t *testing.T) {
   341  	t.Parallel()
   342  	c, s := makeClient(t)
   343  	defer s.Stop()
   344  
   345  	kv := c.KV()
   346  
   347  	// Generate some test keys
   348  	prefix := testKey()
   349  	var keys []string
   350  	for i := 0; i < 100; i++ {
   351  		keys = append(keys, path.Join(prefix, testKey()))
   352  	}
   353  
   354  	// Set values
   355  	value := []byte("test")
   356  	for _, key := range keys {
   357  		p := &KVPair{Key: key, Value: value}
   358  		if _, err := kv.Put(p, nil); err != nil {
   359  			t.Fatalf("err: %v", err)
   360  		}
   361  	}
   362  
   363  	// List the values
   364  	out, meta, err := kv.Keys(prefix, "", nil)
   365  	if err != nil {
   366  		t.Fatalf("err: %v", err)
   367  	}
   368  	if len(out) != len(keys) {
   369  		t.Fatalf("got %d keys", len(out))
   370  	}
   371  	if meta.LastIndex == 0 {
   372  		t.Fatalf("unexpected value: %#v", meta)
   373  	}
   374  
   375  	// Delete all
   376  	if _, err := kv.DeleteTree(prefix, nil); err != nil {
   377  		t.Fatalf("err: %v", err)
   378  	}
   379  
   380  	// List the values
   381  	out, _, err = kv.Keys(prefix, "", nil)
   382  	if err != nil {
   383  		t.Fatalf("err: %v", err)
   384  	}
   385  	if len(out) != 0 {
   386  		t.Fatalf("got %d keys", len(out))
   387  	}
   388  }
   389  
   390  func TestAPI_ClientAcquireRelease(t *testing.T) {
   391  	t.Parallel()
   392  	c, s := makeClient(t)
   393  	defer s.Stop()
   394  
   395  	session := c.Session()
   396  	kv := c.KV()
   397  
   398  	// Make a session
   399  	id, _, err := session.CreateNoChecks(nil, nil)
   400  	if err != nil {
   401  		t.Fatalf("err: %v", err)
   402  	}
   403  	defer session.Destroy(id, nil)
   404  
   405  	// Acquire the key
   406  	key := testKey()
   407  	value := []byte("test")
   408  	p := &KVPair{Key: key, Value: value, Session: id}
   409  	if work, _, err := kv.Acquire(p, nil); err != nil {
   410  		t.Fatalf("err: %v", err)
   411  	} else if !work {
   412  		t.Fatalf("Lock failure")
   413  	}
   414  
   415  	// Get should work
   416  	pair, meta, err := kv.Get(key, nil)
   417  	if err != nil {
   418  		t.Fatalf("err: %v", err)
   419  	}
   420  	if pair == nil {
   421  		t.Fatalf("expected value: %#v", pair)
   422  	}
   423  	if pair.LockIndex != 1 {
   424  		t.Fatalf("Expected lock: %v", pair)
   425  	}
   426  	if pair.Session != id {
   427  		t.Fatalf("Expected lock: %v", pair)
   428  	}
   429  	if meta.LastIndex == 0 {
   430  		t.Fatalf("unexpected value: %#v", meta)
   431  	}
   432  
   433  	// Release
   434  	if work, _, err := kv.Release(p, nil); err != nil {
   435  		t.Fatalf("err: %v", err)
   436  	} else if !work {
   437  		t.Fatalf("Release fail")
   438  	}
   439  
   440  	// Get should work
   441  	pair, meta, err = kv.Get(key, nil)
   442  	if err != nil {
   443  		t.Fatalf("err: %v", err)
   444  	}
   445  	if pair == nil {
   446  		t.Fatalf("expected value: %#v", pair)
   447  	}
   448  	if pair.LockIndex != 1 {
   449  		t.Fatalf("Expected lock: %v", pair)
   450  	}
   451  	if pair.Session != "" {
   452  		t.Fatalf("Expected unlock: %v", pair)
   453  	}
   454  	if meta.LastIndex == 0 {
   455  		t.Fatalf("unexpected value: %#v", meta)
   456  	}
   457  }
   458  
   459  func TestAPI_KVClientTxn(t *testing.T) {
   460  	t.Parallel()
   461  	c, s := makeClient(t)
   462  	defer s.Stop()
   463  
   464  	session := c.Session()
   465  	kv := c.KV()
   466  
   467  	// Make a session.
   468  	id, _, err := session.CreateNoChecks(nil, nil)
   469  	if err != nil {
   470  		t.Fatalf("err: %v", err)
   471  	}
   472  	defer session.Destroy(id, nil)
   473  
   474  	// Acquire and get the key via a transaction, but don't supply a valid
   475  	// session.
   476  	key := testKey()
   477  	value := []byte("test")
   478  	txn := KVTxnOps{
   479  		&KVTxnOp{
   480  			Verb:  KVLock,
   481  			Key:   key,
   482  			Value: value,
   483  		},
   484  		&KVTxnOp{
   485  			Verb: KVGet,
   486  			Key:  key,
   487  		},
   488  	}
   489  	ok, ret, _, err := kv.Txn(txn, nil)
   490  	if err != nil {
   491  		t.Fatalf("err: %v", err)
   492  	} else if ok {
   493  		t.Fatalf("transaction should have failed")
   494  	}
   495  
   496  	if ret == nil || len(ret.Errors) != 2 || len(ret.Results) != 0 {
   497  		t.Fatalf("bad: %v", ret)
   498  	}
   499  	if ret.Errors[0].OpIndex != 0 ||
   500  		!strings.Contains(ret.Errors[0].What, "missing session") ||
   501  		!strings.Contains(ret.Errors[1].What, "doesn't exist") {
   502  		t.Fatalf("bad: %v", ret.Errors[0])
   503  	}
   504  
   505  	// Now poke in a real session and try again.
   506  	txn[0].Session = id
   507  	ok, ret, _, err = kv.Txn(txn, nil)
   508  	if err != nil {
   509  		t.Fatalf("err: %v", err)
   510  	} else if !ok {
   511  		t.Fatalf("transaction failure")
   512  	}
   513  
   514  	if ret == nil || len(ret.Errors) != 0 || len(ret.Results) != 2 {
   515  		t.Fatalf("bad: %v", ret)
   516  	}
   517  	for i, result := range ret.Results {
   518  		var expected []byte
   519  		if i == 1 {
   520  			expected = value
   521  		}
   522  
   523  		if result.Key != key ||
   524  			!bytes.Equal(result.Value, expected) ||
   525  			result.Session != id ||
   526  			result.LockIndex != 1 {
   527  			t.Fatalf("bad: %v", result)
   528  		}
   529  	}
   530  
   531  	// Run a read-only transaction.
   532  	txn = KVTxnOps{
   533  		&KVTxnOp{
   534  			Verb: KVGet,
   535  			Key:  key,
   536  		},
   537  	}
   538  	ok, ret, _, err = kv.Txn(txn, nil)
   539  	if err != nil {
   540  		t.Fatalf("err: %v", err)
   541  	} else if !ok {
   542  		t.Fatalf("transaction failure")
   543  	}
   544  
   545  	if ret == nil || len(ret.Errors) != 0 || len(ret.Results) != 1 {
   546  		t.Fatalf("bad: %v", ret)
   547  	}
   548  	for _, result := range ret.Results {
   549  		if result.Key != key ||
   550  			!bytes.Equal(result.Value, value) ||
   551  			result.Session != id ||
   552  			result.LockIndex != 1 {
   553  			t.Fatalf("bad: %v", result)
   554  		}
   555  	}
   556  
   557  	// Sanity check using the regular GET API.
   558  	pair, meta, err := kv.Get(key, nil)
   559  	if err != nil {
   560  		t.Fatalf("err: %v", err)
   561  	}
   562  	if pair == nil {
   563  		t.Fatalf("expected value: %#v", pair)
   564  	}
   565  	if pair.LockIndex != 1 {
   566  		t.Fatalf("Expected lock: %v", pair)
   567  	}
   568  	if pair.Session != id {
   569  		t.Fatalf("Expected lock: %v", pair)
   570  	}
   571  	if meta.LastIndex == 0 {
   572  		t.Fatalf("unexpected value: %#v", meta)
   573  	}
   574  }