etcd/store/store_test.go

588 lines
19 KiB
Go
Raw Normal View History

2013-10-07 20:44:51 +04:00
/*
Copyright 2013 CoreOS Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
2013-09-29 03:26:19 +04:00
package store
2013-09-03 22:30:42 +04:00
import (
"testing"
"time"
2013-10-20 23:39:29 +04:00
etcdErr "github.com/coreos/etcd/error"
"github.com/stretchr/testify/assert"
2013-09-03 22:30:42 +04:00
)
2013-10-20 23:39:29 +04:00
// Ensure that the store can retrieve an existing value.
func TestStoreGetValue(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
e, err := s.Get("/foo", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "get", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
assert.Equal(t, e.Node.Value, "bar", "")
2013-09-03 22:30:42 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can recrusively retrieve a directory listing.
// Note that hidden files should not be returned.
func TestStoreGetDirectory(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
s.Create("/foo/bar", false, "X", false, Permanent)
s.Create("/foo/_hidden", false, "*", false, Permanent)
s.Create("/foo/baz", true, "", false, Permanent)
s.Create("/foo/baz/bat", false, "Y", false, Permanent)
s.Create("/foo/baz/_hidden", false, "*", false, Permanent)
s.Create("/foo/baz/ttl", false, "Y", false, time.Now().Add(time.Second*3))
e, err := s.Get("/foo", true, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "get", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
assert.Equal(t, len(e.Node.Nodes), 2, "")
assert.Equal(t, e.Node.Nodes[0].Key, "/foo/bar", "")
assert.Equal(t, e.Node.Nodes[0].Value, "X", "")
assert.Equal(t, e.Node.Nodes[0].Dir, false, "")
assert.Equal(t, e.Node.Nodes[1].Key, "/foo/baz", "")
assert.Equal(t, e.Node.Nodes[1].Dir, true, "")
assert.Equal(t, len(e.Node.Nodes[1].Nodes), 2, "")
assert.Equal(t, e.Node.Nodes[1].Nodes[0].Key, "/foo/baz/bat", "")
assert.Equal(t, e.Node.Nodes[1].Nodes[0].Value, "Y", "")
assert.Equal(t, e.Node.Nodes[1].Nodes[0].Dir, false, "")
assert.Equal(t, e.Node.Nodes[1].Nodes[1].Key, "/foo/baz/ttl", "")
assert.Equal(t, e.Node.Nodes[1].Nodes[1].Value, "Y", "")
assert.Equal(t, e.Node.Nodes[1].Nodes[1].Dir, false, "")
assert.Equal(t, e.Node.Nodes[1].Nodes[1].TTL, 3, "")
2013-09-05 07:57:19 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can retrieve a directory in sorted order.
func TestStoreGetSorted(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
s.Create("/foo/x", false, "0", false, Permanent)
s.Create("/foo/z", false, "0", false, Permanent)
s.Create("/foo/y", true, "", false, Permanent)
s.Create("/foo/y/a", false, "0", false, Permanent)
s.Create("/foo/y/b", false, "0", false, Permanent)
e, err := s.Get("/foo", true, true)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Nodes[0].Key, "/foo/x", "")
assert.Equal(t, e.Node.Nodes[1].Key, "/foo/y", "")
assert.Equal(t, e.Node.Nodes[1].Nodes[0].Key, "/foo/y/a", "")
assert.Equal(t, e.Node.Nodes[1].Nodes[1].Key, "/foo/y/b", "")
assert.Equal(t, e.Node.Nodes[2].Key, "/foo/z", "")
2013-10-20 23:39:29 +04:00
}
2013-09-04 07:10:33 +04:00
2013-12-06 05:46:52 +04:00
func TestSet(t *testing.T) {
s := newStore()
// Set /foo=""
e, err := s.Set("/foo", false, "", Permanent)
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "set", "")
assert.Equal(t, e.Node.Key, "/foo", "")
assert.False(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "", "")
assert.Equal(t, e.Node.Value, "", "")
assert.Nil(t, e.Node.Nodes, "")
assert.Nil(t, e.Node.Expiration, "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(1), "")
// Set /foo="bar"
e, err = s.Set("/foo", false, "bar", Permanent)
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "set", "")
assert.Equal(t, e.Node.Key, "/foo", "")
assert.False(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "", "")
assert.Equal(t, e.Node.Value, "bar", "")
assert.Nil(t, e.Node.Nodes, "")
assert.Nil(t, e.Node.Expiration, "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "")
// Set /dir as a directory
e, err = s.Set("/dir", true, "", Permanent)
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "set", "")
assert.Equal(t, e.Node.Key, "/dir", "")
assert.True(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "", "")
assert.Equal(t, e.Node.Value, "", "")
assert.Nil(t, e.Node.Nodes, "")
assert.Nil(t, e.Node.Expiration, "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can create a new key if it doesn't already exist.
func TestStoreCreateValue(t *testing.T) {
s := newStore()
2013-12-06 05:46:52 +04:00
// Create /foo=bar
2013-12-06 02:48:32 +04:00
e, err := s.Create("/foo", false, "bar", false, Permanent)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "create", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
assert.False(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "", "")
assert.Equal(t, e.Node.Value, "bar", "")
assert.Nil(t, e.Node.Nodes, "")
assert.Nil(t, e.Node.Expiration, "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(1), "")
2013-12-06 05:46:52 +04:00
// Create /empty=""
e, err = s.Create("/empty", false, "", false, Permanent)
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "create", "")
assert.Equal(t, e.Node.Key, "/empty", "")
assert.False(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "", "")
assert.Equal(t, e.Node.Value, "", "")
assert.Nil(t, e.Node.Nodes, "")
assert.Nil(t, e.Node.Expiration, "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "")
2013-09-04 07:10:33 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can create a new directory if it doesn't already exist.
func TestStoreCreateDirectory(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 02:48:32 +04:00
e, err := s.Create("/foo", true, "", false, Permanent)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "create", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
assert.True(t, e.Node.Dir, "")
2013-09-03 22:30:42 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store fails to create a key if it already exists.
func TestStoreCreateFailsIfExists(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 05:46:52 +04:00
// create /foo as dir
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
2013-12-06 05:46:52 +04:00
// create /foo as dir again
2013-12-06 02:48:32 +04:00
e, _err := s.Create("/foo", true, "", false, Permanent)
2013-10-20 23:39:29 +04:00
err := _err.(*etcdErr.Error)
assert.Equal(t, err.ErrorCode, etcdErr.EcodeNodeExist, "")
2013-12-06 03:16:01 +04:00
assert.Equal(t, err.Message, "Key already exists", "")
2013-10-20 23:39:29 +04:00
assert.Equal(t, err.Cause, "/foo", "")
assert.Equal(t, err.Index, uint64(1), "")
2013-10-20 23:39:29 +04:00
assert.Nil(t, e, 0, "")
2013-09-03 22:30:42 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can update a key if it already exists.
func TestStoreUpdateValue(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 05:46:52 +04:00
// create /foo=bar
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
2013-12-06 05:46:52 +04:00
// update /foo="bzr"
e, err := s.Update("/foo", "baz", Permanent)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "update", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
assert.False(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "bar", "")
assert.Equal(t, e.Node.Value, "baz", "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "")
e, _ = s.Get("/foo", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "baz", "")
2013-12-06 05:46:52 +04:00
// update /foo=""
e, err = s.Update("/foo", "", Permanent)
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "update", "")
assert.Equal(t, e.Node.Key, "/foo", "")
assert.False(t, e.Node.Dir, "")
assert.Equal(t, e.Node.PrevValue, "baz", "")
assert.Equal(t, e.Node.Value, "", "")
assert.Equal(t, e.Node.TTL, 0, "")
assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
e, _ = s.Get("/foo", false, false)
assert.Equal(t, e.Node.Value, "", "")
2013-09-05 23:38:22 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store cannot update a directory.
func TestStoreUpdateFailsIfDirectory(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
e, _err := s.Update("/foo", "baz", Permanent)
2013-10-20 23:39:29 +04:00
err := _err.(*etcdErr.Error)
assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "")
2013-12-06 03:16:01 +04:00
assert.Equal(t, err.Message, "Not a file", "")
2013-10-20 23:39:29 +04:00
assert.Equal(t, err.Cause, "/foo", "")
assert.Nil(t, e, "")
2013-09-07 09:05:11 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can update the TTL on a value.
func TestStoreUpdateValueTTL(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-11-12 09:31:12 +04:00
c := make(chan bool)
defer func() {
c <- true
}()
go mockSyncService(s.DeleteExpiredKeys, c)
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
_, err := s.Update("/foo", "baz", time.Now().Add(500*time.Millisecond))
e, _ := s.Get("/foo", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "baz", "")
2013-10-28 20:42:54 +04:00
2013-11-06 09:47:25 +04:00
time.Sleep(600 * time.Millisecond)
e, err = s.Get("/foo", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, e, "")
assert.Equal(t, err.(*etcdErr.Error).ErrorCode, etcdErr.EcodeKeyNotFound, "")
}
2013-09-09 05:14:31 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can update the TTL on a directory.
func TestStoreUpdateDirTTL(t *testing.T) {
s := newStore()
2013-11-12 09:31:12 +04:00
c := make(chan bool)
defer func() {
c <- true
}()
go mockSyncService(s.DeleteExpiredKeys, c)
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
s.Create("/foo/bar", false, "baz", false, Permanent)
_, err := s.Update("/foo", "", time.Now().Add(500*time.Millisecond))
e, _ := s.Get("/foo/bar", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "baz", "")
2013-10-28 20:42:54 +04:00
2013-11-06 09:47:25 +04:00
time.Sleep(600 * time.Millisecond)
e, err = s.Get("/foo/bar", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, e, "")
assert.Equal(t, err.(*etcdErr.Error).ErrorCode, etcdErr.EcodeKeyNotFound, "")
}
2013-09-09 05:14:31 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can delete a value.
func TestStoreDeleteValue(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
e, err := s.Delete("/foo", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "delete", "")
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can delete a directory if recursive is specified.
func TestStoreDeleteDiretory(t *testing.T) {
s := newStore()
2013-12-06 05:46:52 +04:00
// create directory /foo
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
2013-12-06 05:46:52 +04:00
// delete /foo with dir = true and recursive = false
2013-12-09 20:33:55 +04:00
// this should succeed, since the directory is empty
2013-12-06 05:46:52 +04:00
e, err := s.Delete("/foo", true, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "delete", "")
2013-12-06 05:46:52 +04:00
// create directory /foo and directory /foo/bar
s.Create("/foo/bar", true, "", false, Permanent)
// delete /foo with dir = true and recursive = false
// this should fail, since the directory is not empty
_, err = s.Delete("/foo", true, false)
assert.NotNil(t, err, "")
// delete /foo with dir=false and recursive = true
2013-12-09 20:33:55 +04:00
// this should succeed, since recursive implies dir=true
2013-12-06 05:46:52 +04:00
// and recursively delete should be able to delete all
// items under the given directory
e, err = s.Delete("/foo", false, true)
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "delete", "")
}
// Ensure that the store cannot delete a directory if both of recursive
// and dir are not specified.
func TestStoreDeleteDiretoryFailsIfNonRecursiveAndDir(t *testing.T) {
s := newStore()
s.Create("/foo", true, "", false, Permanent)
e, _err := s.Delete("/foo", false, false)
err := _err.(*etcdErr.Error)
assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "")
assert.Equal(t, err.Message, "Not a file", "")
assert.Nil(t, e, "")
2013-10-20 23:39:29 +04:00
}
2013-12-02 03:16:32 +04:00
func TestRootRdOnly(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
_, err := s.Set("/", true, "", Permanent)
2013-12-02 03:16:32 +04:00
assert.NotNil(t, err, "")
2013-12-06 02:48:32 +04:00
_, err = s.Delete("/", true, true)
2013-12-02 03:16:32 +04:00
assert.NotNil(t, err, "")
2013-12-06 02:48:32 +04:00
_, err = s.Create("/", true, "", false, Permanent)
2013-12-02 03:16:32 +04:00
assert.NotNil(t, err, "")
_, err = s.Update("/", "", Permanent)
assert.NotNil(t, err, "")
_, err = s.CompareAndSwap("/", "", 0, "", Permanent)
assert.NotNil(t, err, "")
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can conditionally update a key if it has a previous value.
func TestStoreCompareAndSwapPrevValue(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
e, err := s.CompareAndSwap("/foo", "bar", 0, "baz", Permanent)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "compareAndSwap", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.PrevValue, "bar", "")
assert.Equal(t, e.Node.Value, "baz", "")
e, _ = s.Get("/foo", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "baz", "")
}
2013-10-20 23:39:29 +04:00
// Ensure that the store cannot conditionally update a key if it has the wrong previous value.
func TestStoreCompareAndSwapPrevValueFailsIfNotMatch(t *testing.T) {
2013-10-14 21:12:30 +04:00
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
e, _err := s.CompareAndSwap("/foo", "wrong_value", 0, "baz", Permanent)
2013-10-20 23:39:29 +04:00
err := _err.(*etcdErr.Error)
assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "")
2013-12-06 03:16:01 +04:00
assert.Equal(t, err.Message, "Compare failed", "")
2013-10-20 23:39:29 +04:00
assert.Nil(t, e, "")
e, _ = s.Get("/foo", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "bar", "")
2013-10-20 23:39:29 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can conditionally update a key if it has a previous index.
func TestStoreCompareAndSwapPrevIndex(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
e, err := s.CompareAndSwap("/foo", "", 1, "baz", Permanent)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
assert.Equal(t, e.Action, "compareAndSwap", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.PrevValue, "bar", "")
assert.Equal(t, e.Node.Value, "baz", "")
e, _ = s.Get("/foo", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "baz", "")
2013-10-20 23:39:29 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store cannot conditionally update a key if it has the wrong previous index.
func TestStoreCompareAndSwapPrevIndexFailsIfNotMatch(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
e, _err := s.CompareAndSwap("/foo", "", 100, "baz", Permanent)
2013-10-20 23:39:29 +04:00
err := _err.(*etcdErr.Error)
assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "")
2013-12-06 03:16:01 +04:00
assert.Equal(t, err.Message, "Compare failed", "")
2013-10-20 23:39:29 +04:00
assert.Nil(t, e, "")
e, _ = s.Get("/foo", false, false)
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "bar", "")
2013-10-20 23:39:29 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for key creation.
func TestStoreWatchCreate(t *testing.T) {
s := newStore()
c, _ := s.Watch("/foo", false, 0)
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "create", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
2013-10-20 23:39:29 +04:00
e = nbselect(c)
assert.Nil(t, e, "")
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for recursive key creation.
func TestStoreWatchRecursiveCreate(t *testing.T) {
s := newStore()
c, _ := s.Watch("/foo", true, 0)
2013-12-06 02:48:32 +04:00
s.Create("/foo/bar", false, "baz", false, Permanent)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "create", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo/bar", "")
2013-10-20 23:39:29 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for key updates.
func TestStoreWatchUpdate(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
c, _ := s.Watch("/foo", false, 0)
s.Update("/foo", "baz", Permanent)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "update", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
2013-10-20 23:39:29 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for recursive key updates.
func TestStoreWatchRecursiveUpdate(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo/bar", false, "baz", false, Permanent)
c, _ := s.Watch("/foo", true, 0)
s.Update("/foo/bar", "baz", Permanent)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "update", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo/bar", "")
2013-10-20 23:39:29 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for key deletions.
func TestStoreWatchDelete(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
c, _ := s.Watch("/foo", false, 0)
2013-12-06 02:48:32 +04:00
s.Delete("/foo", false, false)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "delete", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
2013-10-20 23:39:29 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for recursive key deletions.
func TestStoreWatchRecursiveDelete(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo/bar", false, "baz", false, Permanent)
c, _ := s.Watch("/foo", true, 0)
2013-12-06 02:48:32 +04:00
s.Delete("/foo/bar", false, false)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "delete", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo/bar", "")
2013-10-20 23:39:29 +04:00
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for CAS updates.
func TestStoreWatchCompareAndSwap(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, Permanent)
c, _ := s.Watch("/foo", false, 0)
s.CompareAndSwap("/foo", "bar", 0, "baz", Permanent)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "compareAndSwap", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
2013-10-20 23:39:29 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for recursive CAS updates.
func TestStoreWatchRecursiveCompareAndSwap(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo/bar", false, "baz", false, Permanent)
c, _ := s.Watch("/foo", true, 0)
s.CompareAndSwap("/foo/bar", "baz", 0, "bat", Permanent)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Equal(t, e.Action, "compareAndSwap", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo/bar", "")
2013-10-20 23:39:29 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can watch for key expiration.
func TestStoreWatchExpire(t *testing.T) {
s := newStore()
2013-11-12 09:31:12 +04:00
stopChan := make(chan bool)
defer func() {
stopChan <- true
}()
go mockSyncService(s.DeleteExpiredKeys, stopChan)
2013-12-06 02:48:32 +04:00
s.Create("/foo", false, "bar", false, time.Now().Add(500*time.Millisecond))
s.Create("/foofoo", false, "barbarbar", false, time.Now().Add(500*time.Millisecond))
2013-11-07 09:19:37 +04:00
c, _ := s.Watch("/", true, 0)
2013-10-20 23:39:29 +04:00
e := nbselect(c)
assert.Nil(t, e, "")
2013-11-06 09:47:25 +04:00
time.Sleep(600 * time.Millisecond)
2013-10-20 23:39:29 +04:00
e = nbselect(c)
assert.Equal(t, e.Action, "expire", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foo", "")
c, _ = s.Watch("/", true, 4)
2013-11-07 09:19:37 +04:00
e = nbselect(c)
assert.Equal(t, e.Action, "expire", "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Key, "/foofoo", "")
}
2013-10-20 23:39:29 +04:00
// Ensure that the store can recover from a previously saved state.
func TestStoreRecover(t *testing.T) {
s := newStore()
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
s.Create("/foo/x", false, "bar", false, Permanent)
s.Create("/foo/y", false, "baz", false, Permanent)
2013-10-20 23:39:29 +04:00
b, err := s.Save()
2013-10-20 23:39:29 +04:00
s2 := newStore()
s2.Recovery(b)
e, err := s.Get("/foo/x", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "bar", "")
e, err = s.Get("/foo/y", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "baz", "")
2013-09-09 05:14:31 +04:00
}
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
// Ensure that the store can recover from a previously saved state that includes an expiring key.
func TestStoreRecoverWithExpiration(t *testing.T) {
s := newStore()
2013-11-12 09:31:12 +04:00
c := make(chan bool)
defer func() {
c <- true
}()
go mockSyncService(s.DeleteExpiredKeys, c)
2013-12-06 02:48:32 +04:00
s.Create("/foo", true, "", false, Permanent)
s.Create("/foo/x", false, "bar", false, Permanent)
s.Create("/foo/y", false, "baz", false, time.Now().Add(5*time.Millisecond))
2013-10-20 23:39:29 +04:00
b, err := s.Save()
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
time.Sleep(10 * time.Millisecond)
2013-09-14 01:10:40 +04:00
2013-10-20 23:39:29 +04:00
s2 := newStore()
2013-11-12 09:31:12 +04:00
c2 := make(chan bool)
defer func() {
c2 <- true
}()
go mockSyncService(s2.DeleteExpiredKeys, c2)
2013-10-20 23:39:29 +04:00
s2.Recovery(b)
2013-09-14 01:10:40 +04:00
2013-11-06 09:47:25 +04:00
time.Sleep(600 * time.Millisecond)
e, err := s.Get("/foo/x", false, false)
2013-10-20 23:39:29 +04:00
assert.Nil(t, err, "")
2013-11-28 08:04:52 +04:00
assert.Equal(t, e.Node.Value, "bar", "")
2013-09-14 01:10:40 +04:00
e, err = s.Get("/foo/y", false, false)
2013-10-20 23:39:29 +04:00
assert.NotNil(t, err, "")
assert.Nil(t, e, "")
2013-09-14 01:10:40 +04:00
}
2013-10-20 23:39:29 +04:00
// Performs a non-blocking select on an event channel.
func nbselect(c <-chan *Event) *Event {
2013-09-14 01:10:40 +04:00
select {
case e := <-c:
return e
default:
return nil
}
}
2013-11-06 09:47:25 +04:00
2013-11-12 09:31:12 +04:00
func mockSyncService(f func(now time.Time), c chan bool) {
2013-11-06 09:47:25 +04:00
ticker := time.Tick(time.Millisecond * 500)
2013-11-12 09:31:12 +04:00
for {
select {
case <-c:
return
case now := <-ticker:
f(now)
}
2013-11-06 09:47:25 +04:00
}
}