store_test.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. // Copyright 2015 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package v2store_test
  15. import (
  16. "testing"
  17. "time"
  18. "go.etcd.io/etcd/etcdserver/api/v2error"
  19. "go.etcd.io/etcd/etcdserver/api/v2store"
  20. "go.etcd.io/etcd/pkg/testutil"
  21. )
  22. type StoreCloser interface {
  23. v2store.Store
  24. Close()
  25. }
  26. func TestNewStoreWithNamespaces(t *testing.T) {
  27. s := newTestStore(t, "/0", "/1")
  28. defer s.Close()
  29. _, err := s.Get("/0", false, false)
  30. testutil.AssertNil(t, err)
  31. _, err = s.Get("/1", false, false)
  32. testutil.AssertNil(t, err)
  33. }
  34. // Ensure that the store can retrieve an existing value.
  35. func TestStoreGetValue(t *testing.T) {
  36. s := newTestStore(t)
  37. defer s.Close()
  38. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  39. var eidx uint64 = 1
  40. e, err := s.Get("/foo", false, false)
  41. testutil.AssertNil(t, err)
  42. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  43. testutil.AssertEqual(t, e.Action, "get")
  44. testutil.AssertEqual(t, e.Node.Key, "/foo")
  45. testutil.AssertEqual(t, *e.Node.Value, "bar")
  46. }
  47. // Ensure that the store can retrieve a directory in sorted order.
  48. func TestStoreGetSorted(t *testing.T) {
  49. s := newTestStore(t)
  50. defer s.Close()
  51. s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  52. s.Create("/foo/x", false, "0", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  53. s.Create("/foo/z", false, "0", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  54. s.Create("/foo/y", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  55. s.Create("/foo/y/a", false, "0", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  56. s.Create("/foo/y/b", false, "0", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  57. var eidx uint64 = 6
  58. e, err := s.Get("/foo", true, true)
  59. testutil.AssertNil(t, err)
  60. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  61. var yNodes v2store.NodeExterns
  62. sortedStrings := []string{"/foo/x", "/foo/y", "/foo/z"}
  63. for i := range e.Node.Nodes {
  64. node := e.Node.Nodes[i]
  65. if node.Key != sortedStrings[i] {
  66. t.Errorf("expect key = %s, got key = %s", sortedStrings[i], node.Key)
  67. }
  68. if node.Key == "/foo/y" {
  69. yNodes = node.Nodes
  70. }
  71. }
  72. sortedStrings = []string{"/foo/y/a", "/foo/y/b"}
  73. for i := range yNodes {
  74. node := yNodes[i]
  75. if node.Key != sortedStrings[i] {
  76. t.Errorf("expect key = %s, got key = %s", sortedStrings[i], node.Key)
  77. }
  78. }
  79. }
  80. func TestSet(t *testing.T) {
  81. s := newTestStore(t)
  82. defer s.Close()
  83. // Set /foo=""
  84. var eidx uint64 = 1
  85. e, err := s.Set("/foo", false, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  86. testutil.AssertNil(t, err)
  87. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  88. testutil.AssertEqual(t, e.Action, "set")
  89. testutil.AssertEqual(t, e.Node.Key, "/foo")
  90. testutil.AssertFalse(t, e.Node.Dir)
  91. testutil.AssertEqual(t, *e.Node.Value, "")
  92. testutil.AssertNil(t, e.Node.Nodes)
  93. testutil.AssertNil(t, e.Node.Expiration)
  94. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  95. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(1))
  96. // Set /foo="bar"
  97. eidx = 2
  98. e, err = s.Set("/foo", false, "bar", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  99. testutil.AssertNil(t, err)
  100. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  101. testutil.AssertEqual(t, e.Action, "set")
  102. testutil.AssertEqual(t, e.Node.Key, "/foo")
  103. testutil.AssertFalse(t, e.Node.Dir)
  104. testutil.AssertEqual(t, *e.Node.Value, "bar")
  105. testutil.AssertNil(t, e.Node.Nodes)
  106. testutil.AssertNil(t, e.Node.Expiration)
  107. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  108. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(2))
  109. // check prevNode
  110. testutil.AssertNotNil(t, e.PrevNode)
  111. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  112. testutil.AssertEqual(t, *e.PrevNode.Value, "")
  113. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(1))
  114. // Set /foo="baz" (for testing prevNode)
  115. eidx = 3
  116. e, err = s.Set("/foo", false, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  117. testutil.AssertNil(t, err)
  118. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  119. testutil.AssertEqual(t, e.Action, "set")
  120. testutil.AssertEqual(t, e.Node.Key, "/foo")
  121. testutil.AssertFalse(t, e.Node.Dir)
  122. testutil.AssertEqual(t, *e.Node.Value, "baz")
  123. testutil.AssertNil(t, e.Node.Nodes)
  124. testutil.AssertNil(t, e.Node.Expiration)
  125. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  126. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(3))
  127. // check prevNode
  128. testutil.AssertNotNil(t, e.PrevNode)
  129. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  130. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  131. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(2))
  132. // Set /a/b/c/d="efg"
  133. eidx = 4
  134. e, err = s.Set("/a/b/c/d", false, "efg", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  135. testutil.AssertNil(t, err)
  136. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  137. testutil.AssertEqual(t, e.Node.Key, "/a/b/c/d")
  138. testutil.AssertFalse(t, e.Node.Dir)
  139. testutil.AssertEqual(t, *e.Node.Value, "efg")
  140. testutil.AssertNil(t, e.Node.Nodes)
  141. testutil.AssertNil(t, e.Node.Expiration)
  142. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  143. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(4))
  144. // Set /dir as a directory
  145. eidx = 5
  146. e, err = s.Set("/dir", true, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  147. testutil.AssertNil(t, err)
  148. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  149. testutil.AssertEqual(t, e.Action, "set")
  150. testutil.AssertEqual(t, e.Node.Key, "/dir")
  151. testutil.AssertTrue(t, e.Node.Dir)
  152. testutil.AssertNil(t, e.Node.Value)
  153. testutil.AssertNil(t, e.Node.Nodes)
  154. testutil.AssertNil(t, e.Node.Expiration)
  155. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  156. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(5))
  157. }
  158. // Ensure that the store can create a new key if it doesn't already exist.
  159. func TestStoreCreateValue(t *testing.T) {
  160. s := newTestStore(t)
  161. defer s.Close()
  162. // Create /foo=bar
  163. var eidx uint64 = 1
  164. e, err := s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  165. testutil.AssertNil(t, err)
  166. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  167. testutil.AssertEqual(t, e.Action, "create")
  168. testutil.AssertEqual(t, e.Node.Key, "/foo")
  169. testutil.AssertFalse(t, e.Node.Dir)
  170. testutil.AssertEqual(t, *e.Node.Value, "bar")
  171. testutil.AssertNil(t, e.Node.Nodes)
  172. testutil.AssertNil(t, e.Node.Expiration)
  173. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  174. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(1))
  175. // Create /empty=""
  176. eidx = 2
  177. e, err = s.Create("/empty", false, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  178. testutil.AssertNil(t, err)
  179. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  180. testutil.AssertEqual(t, e.Action, "create")
  181. testutil.AssertEqual(t, e.Node.Key, "/empty")
  182. testutil.AssertFalse(t, e.Node.Dir)
  183. testutil.AssertEqual(t, *e.Node.Value, "")
  184. testutil.AssertNil(t, e.Node.Nodes)
  185. testutil.AssertNil(t, e.Node.Expiration)
  186. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  187. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(2))
  188. }
  189. // Ensure that the store can create a new directory if it doesn't already exist.
  190. func TestStoreCreateDirectory(t *testing.T) {
  191. s := newTestStore(t)
  192. defer s.Close()
  193. var eidx uint64 = 1
  194. e, err := s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  195. testutil.AssertNil(t, err)
  196. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  197. testutil.AssertEqual(t, e.Action, "create")
  198. testutil.AssertEqual(t, e.Node.Key, "/foo")
  199. testutil.AssertTrue(t, e.Node.Dir)
  200. }
  201. // Ensure that the store fails to create a key if it already exists.
  202. func TestStoreCreateFailsIfExists(t *testing.T) {
  203. s := newTestStore(t)
  204. defer s.Close()
  205. // create /foo as dir
  206. s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  207. // create /foo as dir again
  208. e, _err := s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  209. err := _err.(*v2error.Error)
  210. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeNodeExist)
  211. testutil.AssertEqual(t, err.Message, "Key already exists")
  212. testutil.AssertEqual(t, err.Cause, "/foo")
  213. testutil.AssertEqual(t, err.Index, uint64(1))
  214. testutil.AssertNil(t, e)
  215. }
  216. // Ensure that the store can update a key if it already exists.
  217. func TestStoreUpdateValue(t *testing.T) {
  218. s := newTestStore(t)
  219. defer s.Close()
  220. // create /foo=bar
  221. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  222. // update /foo="bzr"
  223. var eidx uint64 = 2
  224. e, err := s.Update("/foo", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  225. testutil.AssertNil(t, err)
  226. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  227. testutil.AssertEqual(t, e.Action, "update")
  228. testutil.AssertEqual(t, e.Node.Key, "/foo")
  229. testutil.AssertFalse(t, e.Node.Dir)
  230. testutil.AssertEqual(t, *e.Node.Value, "baz")
  231. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  232. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(2))
  233. // check prevNode
  234. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  235. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  236. testutil.AssertEqual(t, e.PrevNode.TTL, int64(0))
  237. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(1))
  238. e, _ = s.Get("/foo", false, false)
  239. testutil.AssertEqual(t, *e.Node.Value, "baz")
  240. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  241. // update /foo=""
  242. eidx = 3
  243. e, err = s.Update("/foo", "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  244. testutil.AssertNil(t, err)
  245. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  246. testutil.AssertEqual(t, e.Action, "update")
  247. testutil.AssertEqual(t, e.Node.Key, "/foo")
  248. testutil.AssertFalse(t, e.Node.Dir)
  249. testutil.AssertEqual(t, *e.Node.Value, "")
  250. testutil.AssertEqual(t, e.Node.TTL, int64(0))
  251. testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(3))
  252. // check prevNode
  253. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  254. testutil.AssertEqual(t, *e.PrevNode.Value, "baz")
  255. testutil.AssertEqual(t, e.PrevNode.TTL, int64(0))
  256. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(2))
  257. e, _ = s.Get("/foo", false, false)
  258. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  259. testutil.AssertEqual(t, *e.Node.Value, "")
  260. }
  261. // Ensure that the store cannot update a directory.
  262. func TestStoreUpdateFailsIfDirectory(t *testing.T) {
  263. s := newTestStore(t)
  264. defer s.Close()
  265. s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  266. e, _err := s.Update("/foo", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  267. err := _err.(*v2error.Error)
  268. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeNotFile)
  269. testutil.AssertEqual(t, err.Message, "Not a file")
  270. testutil.AssertEqual(t, err.Cause, "/foo")
  271. testutil.AssertNil(t, e)
  272. }
  273. // Ensure that the store can delete a value.
  274. func TestStoreDeleteValue(t *testing.T) {
  275. s := newTestStore(t)
  276. defer s.Close()
  277. var eidx uint64 = 2
  278. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  279. e, err := s.Delete("/foo", false, false)
  280. testutil.AssertNil(t, err)
  281. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  282. testutil.AssertEqual(t, e.Action, "delete")
  283. // check prevNode
  284. testutil.AssertNotNil(t, e.PrevNode)
  285. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  286. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  287. }
  288. // Ensure that the store can delete a directory if recursive is specified.
  289. func TestStoreDeleteDirectory(t *testing.T) {
  290. s := newTestStore(t)
  291. defer s.Close()
  292. // create directory /foo
  293. var eidx uint64 = 2
  294. s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  295. // delete /foo with dir = true and recursive = false
  296. // this should succeed, since the directory is empty
  297. e, err := s.Delete("/foo", true, false)
  298. testutil.AssertNil(t, err)
  299. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  300. testutil.AssertEqual(t, e.Action, "delete")
  301. // check prevNode
  302. testutil.AssertNotNil(t, e.PrevNode)
  303. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  304. testutil.AssertEqual(t, e.PrevNode.Dir, true)
  305. // create directory /foo and directory /foo/bar
  306. _, err = s.Create("/foo/bar", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  307. testutil.AssertNil(t, err)
  308. // delete /foo with dir = true and recursive = false
  309. // this should fail, since the directory is not empty
  310. _, err = s.Delete("/foo", true, false)
  311. testutil.AssertNotNil(t, err)
  312. // delete /foo with dir=false and recursive = true
  313. // this should succeed, since recursive implies dir=true
  314. // and recursively delete should be able to delete all
  315. // items under the given directory
  316. e, err = s.Delete("/foo", false, true)
  317. testutil.AssertNil(t, err)
  318. testutil.AssertEqual(t, e.Action, "delete")
  319. }
  320. // Ensure that the store cannot delete a directory if both of recursive
  321. // and dir are not specified.
  322. func TestStoreDeleteDirectoryFailsIfNonRecursiveAndDir(t *testing.T) {
  323. s := newTestStore(t)
  324. defer s.Close()
  325. s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  326. e, _err := s.Delete("/foo", false, false)
  327. err := _err.(*v2error.Error)
  328. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeNotFile)
  329. testutil.AssertEqual(t, err.Message, "Not a file")
  330. testutil.AssertNil(t, e)
  331. }
  332. func TestRootRdOnly(t *testing.T) {
  333. s := newTestStore(t, "/0")
  334. defer s.Close()
  335. for _, tt := range []string{"/", "/0"} {
  336. _, err := s.Set(tt, true, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  337. testutil.AssertNotNil(t, err)
  338. _, err = s.Delete(tt, true, true)
  339. testutil.AssertNotNil(t, err)
  340. _, err = s.Create(tt, true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  341. testutil.AssertNotNil(t, err)
  342. _, err = s.Update(tt, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  343. testutil.AssertNotNil(t, err)
  344. _, err = s.CompareAndSwap(tt, "", 0, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  345. testutil.AssertNotNil(t, err)
  346. }
  347. }
  348. func TestStoreCompareAndDeletePrevValue(t *testing.T) {
  349. s := newTestStore(t)
  350. defer s.Close()
  351. var eidx uint64 = 2
  352. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  353. e, err := s.CompareAndDelete("/foo", "bar", 0)
  354. testutil.AssertNil(t, err)
  355. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  356. testutil.AssertEqual(t, e.Action, "compareAndDelete")
  357. testutil.AssertEqual(t, e.Node.Key, "/foo")
  358. // check prevNode
  359. testutil.AssertNotNil(t, e.PrevNode)
  360. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  361. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  362. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(1))
  363. testutil.AssertEqual(t, e.PrevNode.CreatedIndex, uint64(1))
  364. }
  365. func TestStoreCompareAndDeletePrevValueFailsIfNotMatch(t *testing.T) {
  366. s := newTestStore(t)
  367. defer s.Close()
  368. var eidx uint64 = 1
  369. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  370. e, _err := s.CompareAndDelete("/foo", "baz", 0)
  371. err := _err.(*v2error.Error)
  372. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeTestFailed)
  373. testutil.AssertEqual(t, err.Message, "Compare failed")
  374. testutil.AssertNil(t, e)
  375. e, _ = s.Get("/foo", false, false)
  376. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  377. testutil.AssertEqual(t, *e.Node.Value, "bar")
  378. }
  379. func TestStoreCompareAndDeletePrevIndex(t *testing.T) {
  380. s := newTestStore(t)
  381. defer s.Close()
  382. var eidx uint64 = 2
  383. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  384. e, err := s.CompareAndDelete("/foo", "", 1)
  385. testutil.AssertNil(t, err)
  386. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  387. testutil.AssertEqual(t, e.Action, "compareAndDelete")
  388. // check prevNode
  389. testutil.AssertNotNil(t, e.PrevNode)
  390. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  391. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  392. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(1))
  393. testutil.AssertEqual(t, e.PrevNode.CreatedIndex, uint64(1))
  394. }
  395. func TestStoreCompareAndDeletePrevIndexFailsIfNotMatch(t *testing.T) {
  396. s := newTestStore(t)
  397. defer s.Close()
  398. var eidx uint64 = 1
  399. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  400. e, _err := s.CompareAndDelete("/foo", "", 100)
  401. testutil.AssertNotNil(t, _err)
  402. err := _err.(*v2error.Error)
  403. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeTestFailed)
  404. testutil.AssertEqual(t, err.Message, "Compare failed")
  405. testutil.AssertNil(t, e)
  406. e, _ = s.Get("/foo", false, false)
  407. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  408. testutil.AssertEqual(t, *e.Node.Value, "bar")
  409. }
  410. // Ensure that the store cannot delete a directory.
  411. func TestStoreCompareAndDeleteDirectoryFail(t *testing.T) {
  412. s := newTestStore(t)
  413. defer s.Close()
  414. s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  415. _, _err := s.CompareAndDelete("/foo", "", 0)
  416. testutil.AssertNotNil(t, _err)
  417. err := _err.(*v2error.Error)
  418. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeNotFile)
  419. }
  420. // Ensure that the store can conditionally update a key if it has a previous value.
  421. func TestStoreCompareAndSwapPrevValue(t *testing.T) {
  422. s := newTestStore(t)
  423. defer s.Close()
  424. var eidx uint64 = 2
  425. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  426. e, err := s.CompareAndSwap("/foo", "bar", 0, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  427. testutil.AssertNil(t, err)
  428. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  429. testutil.AssertEqual(t, e.Action, "compareAndSwap")
  430. testutil.AssertEqual(t, *e.Node.Value, "baz")
  431. // check prevNode
  432. testutil.AssertNotNil(t, e.PrevNode)
  433. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  434. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  435. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(1))
  436. testutil.AssertEqual(t, e.PrevNode.CreatedIndex, uint64(1))
  437. e, _ = s.Get("/foo", false, false)
  438. testutil.AssertEqual(t, *e.Node.Value, "baz")
  439. }
  440. // Ensure that the store cannot conditionally update a key if it has the wrong previous value.
  441. func TestStoreCompareAndSwapPrevValueFailsIfNotMatch(t *testing.T) {
  442. s := newTestStore(t)
  443. defer s.Close()
  444. var eidx uint64 = 1
  445. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  446. e, _err := s.CompareAndSwap("/foo", "wrong_value", 0, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  447. err := _err.(*v2error.Error)
  448. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeTestFailed)
  449. testutil.AssertEqual(t, err.Message, "Compare failed")
  450. testutil.AssertNil(t, e)
  451. e, _ = s.Get("/foo", false, false)
  452. testutil.AssertEqual(t, *e.Node.Value, "bar")
  453. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  454. }
  455. // Ensure that the store can conditionally update a key if it has a previous index.
  456. func TestStoreCompareAndSwapPrevIndex(t *testing.T) {
  457. s := newTestStore(t)
  458. defer s.Close()
  459. var eidx uint64 = 2
  460. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  461. e, err := s.CompareAndSwap("/foo", "", 1, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  462. testutil.AssertNil(t, err)
  463. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  464. testutil.AssertEqual(t, e.Action, "compareAndSwap")
  465. testutil.AssertEqual(t, *e.Node.Value, "baz")
  466. // check prevNode
  467. testutil.AssertNotNil(t, e.PrevNode)
  468. testutil.AssertEqual(t, e.PrevNode.Key, "/foo")
  469. testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
  470. testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(1))
  471. testutil.AssertEqual(t, e.PrevNode.CreatedIndex, uint64(1))
  472. e, _ = s.Get("/foo", false, false)
  473. testutil.AssertEqual(t, *e.Node.Value, "baz")
  474. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  475. }
  476. // Ensure that the store cannot conditionally update a key if it has the wrong previous index.
  477. func TestStoreCompareAndSwapPrevIndexFailsIfNotMatch(t *testing.T) {
  478. s := newTestStore(t)
  479. defer s.Close()
  480. var eidx uint64 = 1
  481. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  482. e, _err := s.CompareAndSwap("/foo", "", 100, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  483. err := _err.(*v2error.Error)
  484. testutil.AssertEqual(t, err.ErrorCode, v2error.EcodeTestFailed)
  485. testutil.AssertEqual(t, err.Message, "Compare failed")
  486. testutil.AssertNil(t, e)
  487. e, _ = s.Get("/foo", false, false)
  488. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  489. testutil.AssertEqual(t, *e.Node.Value, "bar")
  490. }
  491. // Ensure that the store can watch for key creation.
  492. func TestStoreWatchCreate(t *testing.T) {
  493. s := newTestStore(t)
  494. defer s.Close()
  495. var eidx uint64 = 0
  496. w, _ := s.Watch("/foo", false, false, 0)
  497. c := w.EventChan()
  498. testutil.AssertEqual(t, w.StartIndex(), eidx)
  499. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  500. eidx = 1
  501. e := timeoutSelect(t, c)
  502. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  503. testutil.AssertEqual(t, e.Action, "create")
  504. testutil.AssertEqual(t, e.Node.Key, "/foo")
  505. select {
  506. case e = <-w.EventChan():
  507. testutil.AssertNil(t, e)
  508. case <-time.After(100 * time.Millisecond):
  509. }
  510. }
  511. // Ensure that the store can watch for recursive key creation.
  512. func TestStoreWatchRecursiveCreate(t *testing.T) {
  513. s := newTestStore(t)
  514. defer s.Close()
  515. var eidx uint64 = 0
  516. w, err := s.Watch("/foo", true, false, 0)
  517. testutil.AssertNil(t, err)
  518. testutil.AssertEqual(t, w.StartIndex(), eidx)
  519. eidx = 1
  520. s.Create("/foo/bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  521. e := timeoutSelect(t, w.EventChan())
  522. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  523. testutil.AssertEqual(t, e.Action, "create")
  524. testutil.AssertEqual(t, e.Node.Key, "/foo/bar")
  525. }
  526. // Ensure that the store can watch for key updates.
  527. func TestStoreWatchUpdate(t *testing.T) {
  528. s := newTestStore(t)
  529. defer s.Close()
  530. var eidx uint64 = 1
  531. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  532. w, _ := s.Watch("/foo", false, false, 0)
  533. testutil.AssertEqual(t, w.StartIndex(), eidx)
  534. eidx = 2
  535. s.Update("/foo", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  536. e := timeoutSelect(t, w.EventChan())
  537. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  538. testutil.AssertEqual(t, e.Action, "update")
  539. testutil.AssertEqual(t, e.Node.Key, "/foo")
  540. }
  541. // Ensure that the store can watch for recursive key updates.
  542. func TestStoreWatchRecursiveUpdate(t *testing.T) {
  543. s := newTestStore(t)
  544. defer s.Close()
  545. var eidx uint64 = 1
  546. s.Create("/foo/bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  547. w, err := s.Watch("/foo", true, false, 0)
  548. testutil.AssertNil(t, err)
  549. testutil.AssertEqual(t, w.StartIndex(), eidx)
  550. eidx = 2
  551. s.Update("/foo/bar", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  552. e := timeoutSelect(t, w.EventChan())
  553. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  554. testutil.AssertEqual(t, e.Action, "update")
  555. testutil.AssertEqual(t, e.Node.Key, "/foo/bar")
  556. }
  557. // Ensure that the store can watch for key deletions.
  558. func TestStoreWatchDelete(t *testing.T) {
  559. s := newTestStore(t)
  560. defer s.Close()
  561. var eidx uint64 = 1
  562. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  563. w, _ := s.Watch("/foo", false, false, 0)
  564. testutil.AssertEqual(t, w.StartIndex(), eidx)
  565. eidx = 2
  566. s.Delete("/foo", false, false)
  567. e := timeoutSelect(t, w.EventChan())
  568. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  569. testutil.AssertEqual(t, e.Action, "delete")
  570. testutil.AssertEqual(t, e.Node.Key, "/foo")
  571. }
  572. // Ensure that the store can watch for recursive key deletions.
  573. func TestStoreWatchRecursiveDelete(t *testing.T) {
  574. s := newTestStore(t)
  575. defer s.Close()
  576. var eidx uint64 = 1
  577. s.Create("/foo/bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  578. w, err := s.Watch("/foo", true, false, 0)
  579. testutil.AssertNil(t, err)
  580. testutil.AssertEqual(t, w.StartIndex(), eidx)
  581. eidx = 2
  582. s.Delete("/foo/bar", false, false)
  583. e := timeoutSelect(t, w.EventChan())
  584. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  585. testutil.AssertEqual(t, e.Action, "delete")
  586. testutil.AssertEqual(t, e.Node.Key, "/foo/bar")
  587. }
  588. // Ensure that the store can watch for CAS updates.
  589. func TestStoreWatchCompareAndSwap(t *testing.T) {
  590. s := newTestStore(t)
  591. defer s.Close()
  592. var eidx uint64 = 1
  593. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  594. w, _ := s.Watch("/foo", false, false, 0)
  595. testutil.AssertEqual(t, w.StartIndex(), eidx)
  596. eidx = 2
  597. s.CompareAndSwap("/foo", "bar", 0, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  598. e := timeoutSelect(t, w.EventChan())
  599. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  600. testutil.AssertEqual(t, e.Action, "compareAndSwap")
  601. testutil.AssertEqual(t, e.Node.Key, "/foo")
  602. }
  603. // Ensure that the store can watch for recursive CAS updates.
  604. func TestStoreWatchRecursiveCompareAndSwap(t *testing.T) {
  605. s := newTestStore(t)
  606. defer s.Close()
  607. var eidx uint64 = 1
  608. s.Create("/foo/bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  609. w, _ := s.Watch("/foo", true, false, 0)
  610. testutil.AssertEqual(t, w.StartIndex(), eidx)
  611. eidx = 2
  612. s.CompareAndSwap("/foo/bar", "baz", 0, "bat", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  613. e := timeoutSelect(t, w.EventChan())
  614. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  615. testutil.AssertEqual(t, e.Action, "compareAndSwap")
  616. testutil.AssertEqual(t, e.Node.Key, "/foo/bar")
  617. }
  618. // Ensure that the store can watch in streaming mode.
  619. func TestStoreWatchStream(t *testing.T) {
  620. s := newTestStore(t)
  621. defer s.Close()
  622. var eidx uint64 = 1
  623. w, _ := s.Watch("/foo", false, true, 0)
  624. // first modification
  625. s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  626. e := timeoutSelect(t, w.EventChan())
  627. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  628. testutil.AssertEqual(t, e.Action, "create")
  629. testutil.AssertEqual(t, e.Node.Key, "/foo")
  630. testutil.AssertEqual(t, *e.Node.Value, "bar")
  631. select {
  632. case e = <-w.EventChan():
  633. testutil.AssertNil(t, e)
  634. case <-time.After(100 * time.Millisecond):
  635. }
  636. // second modification
  637. eidx = 2
  638. s.Update("/foo", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  639. e = timeoutSelect(t, w.EventChan())
  640. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  641. testutil.AssertEqual(t, e.Action, "update")
  642. testutil.AssertEqual(t, e.Node.Key, "/foo")
  643. testutil.AssertEqual(t, *e.Node.Value, "baz")
  644. select {
  645. case e = <-w.EventChan():
  646. testutil.AssertNil(t, e)
  647. case <-time.After(100 * time.Millisecond):
  648. }
  649. }
  650. // Ensure that the store can watch for hidden keys as long as it's an exact path match.
  651. func TestStoreWatchCreateWithHiddenKey(t *testing.T) {
  652. s := newTestStore(t)
  653. defer s.Close()
  654. var eidx uint64 = 1
  655. w, _ := s.Watch("/_foo", false, false, 0)
  656. s.Create("/_foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  657. e := timeoutSelect(t, w.EventChan())
  658. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  659. testutil.AssertEqual(t, e.Action, "create")
  660. testutil.AssertEqual(t, e.Node.Key, "/_foo")
  661. select {
  662. case e = <-w.EventChan():
  663. testutil.AssertNil(t, e)
  664. case <-time.After(100 * time.Millisecond):
  665. }
  666. }
  667. // Ensure that the store doesn't see hidden key creates without an exact path match in recursive mode.
  668. func TestStoreWatchRecursiveCreateWithHiddenKey(t *testing.T) {
  669. s := newTestStore(t)
  670. defer s.Close()
  671. w, _ := s.Watch("/foo", true, false, 0)
  672. s.Create("/foo/_bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  673. e := nbselect(w.EventChan())
  674. testutil.AssertNil(t, e)
  675. w, _ = s.Watch("/foo", true, false, 0)
  676. s.Create("/foo/_baz", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  677. select {
  678. case e = <-w.EventChan():
  679. testutil.AssertNil(t, e)
  680. case <-time.After(100 * time.Millisecond):
  681. }
  682. s.Create("/foo/_baz/quux", false, "quux", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  683. select {
  684. case e = <-w.EventChan():
  685. testutil.AssertNil(t, e)
  686. case <-time.After(100 * time.Millisecond):
  687. }
  688. }
  689. // Ensure that the store doesn't see hidden key updates.
  690. func TestStoreWatchUpdateWithHiddenKey(t *testing.T) {
  691. s := newTestStore(t)
  692. defer s.Close()
  693. s.Create("/_foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  694. w, _ := s.Watch("/_foo", false, false, 0)
  695. s.Update("/_foo", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  696. e := timeoutSelect(t, w.EventChan())
  697. testutil.AssertEqual(t, e.Action, "update")
  698. testutil.AssertEqual(t, e.Node.Key, "/_foo")
  699. e = nbselect(w.EventChan())
  700. testutil.AssertNil(t, e)
  701. }
  702. // Ensure that the store doesn't see hidden key updates without an exact path match in recursive mode.
  703. func TestStoreWatchRecursiveUpdateWithHiddenKey(t *testing.T) {
  704. s := newTestStore(t)
  705. defer s.Close()
  706. s.Create("/foo/_bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  707. w, _ := s.Watch("/foo", true, false, 0)
  708. s.Update("/foo/_bar", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  709. e := nbselect(w.EventChan())
  710. testutil.AssertNil(t, e)
  711. }
  712. // Ensure that the store can watch for key deletions.
  713. func TestStoreWatchDeleteWithHiddenKey(t *testing.T) {
  714. s := newTestStore(t)
  715. defer s.Close()
  716. var eidx uint64 = 2
  717. s.Create("/_foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  718. w, _ := s.Watch("/_foo", false, false, 0)
  719. s.Delete("/_foo", false, false)
  720. e := timeoutSelect(t, w.EventChan())
  721. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  722. testutil.AssertEqual(t, e.Action, "delete")
  723. testutil.AssertEqual(t, e.Node.Key, "/_foo")
  724. e = nbselect(w.EventChan())
  725. testutil.AssertNil(t, e)
  726. }
  727. // Ensure that the store doesn't see hidden key deletes without an exact path match in recursive mode.
  728. func TestStoreWatchRecursiveDeleteWithHiddenKey(t *testing.T) {
  729. s := newTestStore(t)
  730. defer s.Close()
  731. s.Create("/foo/_bar", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  732. w, _ := s.Watch("/foo", true, false, 0)
  733. s.Delete("/foo/_bar", false, false)
  734. e := nbselect(w.EventChan())
  735. testutil.AssertNil(t, e)
  736. }
  737. // Ensure that the store does see hidden key creates if watching deeper than a hidden key in recursive mode.
  738. func TestStoreWatchRecursiveCreateDeeperThanHiddenKey(t *testing.T) {
  739. s := newTestStore(t)
  740. defer s.Close()
  741. var eidx uint64 = 1
  742. w, _ := s.Watch("/_foo/bar", true, false, 0)
  743. s.Create("/_foo/bar/baz", false, "baz", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
  744. e := timeoutSelect(t, w.EventChan())
  745. testutil.AssertNotNil(t, e)
  746. testutil.AssertEqual(t, e.EtcdIndex, eidx)
  747. testutil.AssertEqual(t, e.Action, "create")
  748. testutil.AssertEqual(t, e.Node.Key, "/_foo/bar/baz")
  749. }
  750. // Ensure that slow consumers are handled properly.
  751. //
  752. // Since Watcher.EventChan() has a buffer of size 100 we can only queue 100
  753. // event per watcher. If the consumer cannot consume the event on time and
  754. // another event arrives, the channel is closed and event is discarded.
  755. // This test ensures that after closing the channel, the store can continue
  756. // to operate correctly.
  757. func TestStoreWatchSlowConsumer(t *testing.T) {
  758. s := newTestStore(t)
  759. defer s.Close()
  760. s.Watch("/foo", true, true, 0) // stream must be true
  761. // Fill watch channel with 100 events
  762. for i := 1; i <= 100; i++ {
  763. s.Set("/foo", false, string(i), v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) // ok
  764. }
  765. // testutil.AssertEqual(t, s.WatcherHub.count, int64(1))
  766. s.Set("/foo", false, "101", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) // ok
  767. // remove watcher
  768. // testutil.AssertEqual(t, s.WatcherHub.count, int64(0))
  769. s.Set("/foo", false, "102", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) // must not panic
  770. }
  771. // Performs a non-blocking select on an event channel.
  772. func nbselect(c <-chan *v2store.Event) *v2store.Event {
  773. select {
  774. case e := <-c:
  775. return e
  776. default:
  777. return nil
  778. }
  779. }
  780. // Performs a non-blocking select on an event channel.
  781. func timeoutSelect(t *testing.T, c <-chan *v2store.Event) *v2store.Event {
  782. select {
  783. case e := <-c:
  784. return e
  785. case <-time.After(time.Second):
  786. t.Errorf("timed out waiting on event")
  787. return nil
  788. }
  789. }