store_test.go 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  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 store
  15. import (
  16. "testing"
  17. "time"
  18. etcdErr "github.com/coreos/etcd/error"
  19. "github.com/jonboulle/clockwork"
  20. "github.com/stretchr/testify/assert"
  21. )
  22. func TestNewStoreWithNamespaces(t *testing.T) {
  23. s := newStore("/0", "/1")
  24. _, err := s.Get("/0", false, false)
  25. assert.Nil(t, err, "")
  26. _, err = s.Get("/1", false, false)
  27. assert.Nil(t, err, "")
  28. }
  29. // Ensure that the store can retrieve an existing value.
  30. func TestStoreGetValue(t *testing.T) {
  31. s := newStore()
  32. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  33. var eidx uint64 = 1
  34. e, err := s.Get("/foo", false, false)
  35. assert.Nil(t, err, "")
  36. assert.Equal(t, e.EtcdIndex, eidx, "")
  37. assert.Equal(t, e.Action, "get", "")
  38. assert.Equal(t, e.Node.Key, "/foo", "")
  39. assert.Equal(t, *e.Node.Value, "bar", "")
  40. }
  41. // Ensure that any TTL <= minExpireTime becomes Permanent
  42. func TestMinExpireTime(t *testing.T) {
  43. s := newStore()
  44. fc := clockwork.NewFakeClock()
  45. s.clock = fc
  46. // FakeClock starts at 0, so minExpireTime should be far in the future.. but just in case
  47. assert.True(t, minExpireTime.After(fc.Now()), "minExpireTime should be ahead of FakeClock!")
  48. s.Create("/foo", false, "Y", false, TTLOptionSet{ExpireTime: fc.Now().Add(3 * time.Second)})
  49. fc.Advance(5 * time.Second)
  50. // Ensure it hasn't expired
  51. s.DeleteExpiredKeys(fc.Now())
  52. var eidx uint64 = 1
  53. e, err := s.Get("/foo", true, false)
  54. assert.Nil(t, err, "")
  55. assert.Equal(t, e.EtcdIndex, eidx, "")
  56. assert.Equal(t, e.Action, "get", "")
  57. assert.Equal(t, e.Node.Key, "/foo", "")
  58. assert.Equal(t, e.Node.TTL, int64(0))
  59. }
  60. // Ensure that the store can recursively retrieve a directory listing.
  61. // Note that hidden files should not be returned.
  62. func TestStoreGetDirectory(t *testing.T) {
  63. s := newStore()
  64. fc := newFakeClock()
  65. s.clock = fc
  66. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  67. s.Create("/foo/bar", false, "X", false, TTLOptionSet{ExpireTime: Permanent})
  68. s.Create("/foo/_hidden", false, "*", false, TTLOptionSet{ExpireTime: Permanent})
  69. s.Create("/foo/baz", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  70. s.Create("/foo/baz/bat", false, "Y", false, TTLOptionSet{ExpireTime: Permanent})
  71. s.Create("/foo/baz/_hidden", false, "*", false, TTLOptionSet{ExpireTime: Permanent})
  72. s.Create("/foo/baz/ttl", false, "Y", false, TTLOptionSet{ExpireTime: fc.Now().Add(time.Second * 3)})
  73. var eidx uint64 = 7
  74. e, err := s.Get("/foo", true, false)
  75. assert.Nil(t, err, "")
  76. assert.Equal(t, e.EtcdIndex, eidx, "")
  77. assert.Equal(t, e.Action, "get", "")
  78. assert.Equal(t, e.Node.Key, "/foo", "")
  79. assert.Equal(t, len(e.Node.Nodes), 2, "")
  80. var bazNodes NodeExterns
  81. for _, node := range e.Node.Nodes {
  82. switch node.Key {
  83. case "/foo/bar":
  84. assert.Equal(t, *node.Value, "X", "")
  85. assert.Equal(t, node.Dir, false, "")
  86. case "/foo/baz":
  87. assert.Equal(t, node.Dir, true, "")
  88. assert.Equal(t, len(node.Nodes), 2, "")
  89. bazNodes = node.Nodes
  90. default:
  91. t.Errorf("key = %s, not matched", node.Key)
  92. }
  93. }
  94. for _, node := range bazNodes {
  95. switch node.Key {
  96. case "/foo/baz/bat":
  97. assert.Equal(t, *node.Value, "Y", "")
  98. assert.Equal(t, node.Dir, false, "")
  99. case "/foo/baz/ttl":
  100. assert.Equal(t, *node.Value, "Y", "")
  101. assert.Equal(t, node.Dir, false, "")
  102. assert.Equal(t, node.TTL, int64(3), "")
  103. default:
  104. t.Errorf("key = %s, not matched", node.Key)
  105. }
  106. }
  107. }
  108. // Ensure that the store can retrieve a directory in sorted order.
  109. func TestStoreGetSorted(t *testing.T) {
  110. s := newStore()
  111. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  112. s.Create("/foo/x", false, "0", false, TTLOptionSet{ExpireTime: Permanent})
  113. s.Create("/foo/z", false, "0", false, TTLOptionSet{ExpireTime: Permanent})
  114. s.Create("/foo/y", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  115. s.Create("/foo/y/a", false, "0", false, TTLOptionSet{ExpireTime: Permanent})
  116. s.Create("/foo/y/b", false, "0", false, TTLOptionSet{ExpireTime: Permanent})
  117. var eidx uint64 = 6
  118. e, err := s.Get("/foo", true, true)
  119. assert.Nil(t, err, "")
  120. assert.Equal(t, e.EtcdIndex, eidx, "")
  121. var yNodes NodeExterns
  122. sortedStrings := []string{"/foo/x", "/foo/y", "/foo/z"}
  123. for i := range e.Node.Nodes {
  124. node := e.Node.Nodes[i]
  125. if node.Key != sortedStrings[i] {
  126. t.Errorf("expect key = %s, got key = %s", sortedStrings[i], node.Key)
  127. }
  128. if node.Key == "/foo/y" {
  129. yNodes = node.Nodes
  130. }
  131. }
  132. sortedStrings = []string{"/foo/y/a", "/foo/y/b"}
  133. for i := range yNodes {
  134. node := yNodes[i]
  135. if node.Key != sortedStrings[i] {
  136. t.Errorf("expect key = %s, got key = %s", sortedStrings[i], node.Key)
  137. }
  138. }
  139. }
  140. func TestSet(t *testing.T) {
  141. s := newStore()
  142. // Set /foo=""
  143. var eidx uint64 = 1
  144. e, err := s.Set("/foo", false, "", TTLOptionSet{ExpireTime: Permanent})
  145. assert.Nil(t, err, "")
  146. assert.Equal(t, e.EtcdIndex, eidx, "")
  147. assert.Equal(t, e.Action, "set", "")
  148. assert.Equal(t, e.Node.Key, "/foo", "")
  149. assert.False(t, e.Node.Dir, "")
  150. assert.Equal(t, *e.Node.Value, "", "")
  151. assert.Nil(t, e.Node.Nodes, "")
  152. assert.Nil(t, e.Node.Expiration, "")
  153. assert.Equal(t, e.Node.TTL, int64(0), "")
  154. assert.Equal(t, e.Node.ModifiedIndex, uint64(1), "")
  155. // Set /foo="bar"
  156. eidx = 2
  157. e, err = s.Set("/foo", false, "bar", TTLOptionSet{ExpireTime: Permanent})
  158. assert.Nil(t, err, "")
  159. assert.Equal(t, e.EtcdIndex, eidx, "")
  160. assert.Equal(t, e.Action, "set", "")
  161. assert.Equal(t, e.Node.Key, "/foo", "")
  162. assert.False(t, e.Node.Dir, "")
  163. assert.Equal(t, *e.Node.Value, "bar", "")
  164. assert.Nil(t, e.Node.Nodes, "")
  165. assert.Nil(t, e.Node.Expiration, "")
  166. assert.Equal(t, e.Node.TTL, int64(0), "")
  167. assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "")
  168. // check prevNode
  169. assert.NotNil(t, e.PrevNode, "")
  170. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  171. assert.Equal(t, *e.PrevNode.Value, "", "")
  172. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
  173. // Set /foo="baz" (for testing prevNode)
  174. eidx = 3
  175. e, err = s.Set("/foo", false, "baz", TTLOptionSet{ExpireTime: Permanent})
  176. assert.Nil(t, err, "")
  177. assert.Equal(t, e.EtcdIndex, eidx, "")
  178. assert.Equal(t, e.Action, "set", "")
  179. assert.Equal(t, e.Node.Key, "/foo", "")
  180. assert.False(t, e.Node.Dir, "")
  181. assert.Equal(t, *e.Node.Value, "baz", "")
  182. assert.Nil(t, e.Node.Nodes, "")
  183. assert.Nil(t, e.Node.Expiration, "")
  184. assert.Equal(t, e.Node.TTL, int64(0), "")
  185. assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
  186. // check prevNode
  187. assert.NotNil(t, e.PrevNode, "")
  188. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  189. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  190. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(2), "")
  191. // Set /dir as a directory
  192. eidx = 4
  193. e, err = s.Set("/dir", true, "", TTLOptionSet{ExpireTime: Permanent})
  194. assert.Nil(t, err, "")
  195. assert.Equal(t, e.EtcdIndex, eidx, "")
  196. assert.Equal(t, e.Action, "set", "")
  197. assert.Equal(t, e.Node.Key, "/dir", "")
  198. assert.True(t, e.Node.Dir, "")
  199. assert.Nil(t, e.Node.Value)
  200. assert.Nil(t, e.Node.Nodes, "")
  201. assert.Nil(t, e.Node.Expiration, "")
  202. assert.Equal(t, e.Node.TTL, int64(0), "")
  203. assert.Equal(t, e.Node.ModifiedIndex, uint64(4), "")
  204. }
  205. // Ensure that the store can create a new key if it doesn't already exist.
  206. func TestStoreCreateValue(t *testing.T) {
  207. s := newStore()
  208. // Create /foo=bar
  209. var eidx uint64 = 1
  210. e, err := s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  211. assert.Nil(t, err, "")
  212. assert.Equal(t, e.EtcdIndex, eidx, "")
  213. assert.Equal(t, e.Action, "create", "")
  214. assert.Equal(t, e.Node.Key, "/foo", "")
  215. assert.False(t, e.Node.Dir, "")
  216. assert.Equal(t, *e.Node.Value, "bar", "")
  217. assert.Nil(t, e.Node.Nodes, "")
  218. assert.Nil(t, e.Node.Expiration, "")
  219. assert.Equal(t, e.Node.TTL, int64(0), "")
  220. assert.Equal(t, e.Node.ModifiedIndex, uint64(1), "")
  221. // Create /empty=""
  222. eidx = 2
  223. e, err = s.Create("/empty", false, "", false, TTLOptionSet{ExpireTime: Permanent})
  224. assert.Nil(t, err, "")
  225. assert.Equal(t, e.EtcdIndex, eidx, "")
  226. assert.Equal(t, e.Action, "create", "")
  227. assert.Equal(t, e.Node.Key, "/empty", "")
  228. assert.False(t, e.Node.Dir, "")
  229. assert.Equal(t, *e.Node.Value, "", "")
  230. assert.Nil(t, e.Node.Nodes, "")
  231. assert.Nil(t, e.Node.Expiration, "")
  232. assert.Equal(t, e.Node.TTL, int64(0), "")
  233. assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "")
  234. }
  235. // Ensure that the store can create a new directory if it doesn't already exist.
  236. func TestStoreCreateDirectory(t *testing.T) {
  237. s := newStore()
  238. var eidx uint64 = 1
  239. e, err := s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  240. assert.Nil(t, err, "")
  241. assert.Equal(t, e.EtcdIndex, eidx, "")
  242. assert.Equal(t, e.Action, "create", "")
  243. assert.Equal(t, e.Node.Key, "/foo", "")
  244. assert.True(t, e.Node.Dir, "")
  245. }
  246. // Ensure that the store fails to create a key if it already exists.
  247. func TestStoreCreateFailsIfExists(t *testing.T) {
  248. s := newStore()
  249. // create /foo as dir
  250. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  251. // create /foo as dir again
  252. e, _err := s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  253. err := _err.(*etcdErr.Error)
  254. assert.Equal(t, err.ErrorCode, etcdErr.EcodeNodeExist, "")
  255. assert.Equal(t, err.Message, "Key already exists", "")
  256. assert.Equal(t, err.Cause, "/foo", "")
  257. assert.Equal(t, err.Index, uint64(1), "")
  258. assert.Nil(t, e, 0, "")
  259. }
  260. // Ensure that the store can update a key if it already exists.
  261. func TestStoreUpdateValue(t *testing.T) {
  262. s := newStore()
  263. // create /foo=bar
  264. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  265. // update /foo="bzr"
  266. var eidx uint64 = 2
  267. e, err := s.Update("/foo", "baz", TTLOptionSet{ExpireTime: Permanent})
  268. assert.Nil(t, err, "")
  269. assert.Equal(t, e.EtcdIndex, eidx, "")
  270. assert.Equal(t, e.Action, "update", "")
  271. assert.Equal(t, e.Node.Key, "/foo", "")
  272. assert.False(t, e.Node.Dir, "")
  273. assert.Equal(t, *e.Node.Value, "baz", "")
  274. assert.Equal(t, e.Node.TTL, int64(0), "")
  275. assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "")
  276. // check prevNode
  277. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  278. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  279. assert.Equal(t, e.PrevNode.TTL, int64(0), "")
  280. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
  281. e, _ = s.Get("/foo", false, false)
  282. assert.Equal(t, *e.Node.Value, "baz", "")
  283. assert.Equal(t, e.EtcdIndex, eidx, "")
  284. // update /foo=""
  285. eidx = 3
  286. e, err = s.Update("/foo", "", TTLOptionSet{ExpireTime: Permanent})
  287. assert.Nil(t, err, "")
  288. assert.Equal(t, e.EtcdIndex, eidx, "")
  289. assert.Equal(t, e.Action, "update", "")
  290. assert.Equal(t, e.Node.Key, "/foo", "")
  291. assert.False(t, e.Node.Dir, "")
  292. assert.Equal(t, *e.Node.Value, "", "")
  293. assert.Equal(t, e.Node.TTL, int64(0), "")
  294. assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
  295. // check prevNode
  296. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  297. assert.Equal(t, *e.PrevNode.Value, "baz", "")
  298. assert.Equal(t, e.PrevNode.TTL, int64(0), "")
  299. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(2), "")
  300. e, _ = s.Get("/foo", false, false)
  301. assert.Equal(t, e.EtcdIndex, eidx, "")
  302. assert.Equal(t, *e.Node.Value, "", "")
  303. }
  304. // Ensure that the store cannot update a directory.
  305. func TestStoreUpdateFailsIfDirectory(t *testing.T) {
  306. s := newStore()
  307. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  308. e, _err := s.Update("/foo", "baz", TTLOptionSet{ExpireTime: Permanent})
  309. err := _err.(*etcdErr.Error)
  310. assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "")
  311. assert.Equal(t, err.Message, "Not a file", "")
  312. assert.Equal(t, err.Cause, "/foo", "")
  313. assert.Nil(t, e, "")
  314. }
  315. // Ensure that the store can update the TTL on a value.
  316. func TestStoreUpdateValueTTL(t *testing.T) {
  317. s := newStore()
  318. fc := newFakeClock()
  319. s.clock = fc
  320. var eidx uint64 = 2
  321. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  322. _, err := s.Update("/foo", "baz", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  323. e, _ := s.Get("/foo", false, false)
  324. assert.Equal(t, *e.Node.Value, "baz", "")
  325. assert.Equal(t, e.EtcdIndex, eidx, "")
  326. fc.Advance(600 * time.Millisecond)
  327. s.DeleteExpiredKeys(fc.Now())
  328. e, err = s.Get("/foo", false, false)
  329. assert.Nil(t, e, "")
  330. assert.Equal(t, err.(*etcdErr.Error).ErrorCode, etcdErr.EcodeKeyNotFound, "")
  331. }
  332. // Ensure that the store can update the TTL on a directory.
  333. func TestStoreUpdateDirTTL(t *testing.T) {
  334. s := newStore()
  335. fc := newFakeClock()
  336. s.clock = fc
  337. var eidx uint64 = 3
  338. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  339. s.Create("/foo/bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  340. e, err := s.Update("/foo", "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  341. assert.Equal(t, e.Node.Dir, true, "")
  342. assert.Equal(t, e.EtcdIndex, eidx, "")
  343. e, _ = s.Get("/foo/bar", false, false)
  344. assert.Equal(t, *e.Node.Value, "baz", "")
  345. assert.Equal(t, e.EtcdIndex, eidx, "")
  346. fc.Advance(600 * time.Millisecond)
  347. s.DeleteExpiredKeys(fc.Now())
  348. e, err = s.Get("/foo/bar", false, false)
  349. assert.Nil(t, e, "")
  350. assert.Equal(t, err.(*etcdErr.Error).ErrorCode, etcdErr.EcodeKeyNotFound, "")
  351. }
  352. // Ensure that the store can delete a value.
  353. func TestStoreDeleteValue(t *testing.T) {
  354. s := newStore()
  355. var eidx uint64 = 2
  356. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  357. e, err := s.Delete("/foo", false, false)
  358. assert.Nil(t, err, "")
  359. assert.Equal(t, e.EtcdIndex, eidx, "")
  360. assert.Equal(t, e.Action, "delete", "")
  361. // check prevNode
  362. assert.NotNil(t, e.PrevNode, "")
  363. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  364. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  365. }
  366. // Ensure that the store can delete a directory if recursive is specified.
  367. func TestStoreDeleteDiretory(t *testing.T) {
  368. s := newStore()
  369. // create directory /foo
  370. var eidx uint64 = 2
  371. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  372. // delete /foo with dir = true and recursive = false
  373. // this should succeed, since the directory is empty
  374. e, err := s.Delete("/foo", true, false)
  375. assert.Nil(t, err, "")
  376. assert.Equal(t, e.EtcdIndex, eidx, "")
  377. assert.Equal(t, e.Action, "delete", "")
  378. // check prevNode
  379. assert.NotNil(t, e.PrevNode, "")
  380. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  381. assert.Equal(t, e.PrevNode.Dir, true, "")
  382. // create directory /foo and directory /foo/bar
  383. s.Create("/foo/bar", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  384. // delete /foo with dir = true and recursive = false
  385. // this should fail, since the directory is not empty
  386. _, err = s.Delete("/foo", true, false)
  387. assert.NotNil(t, err, "")
  388. // delete /foo with dir=false and recursive = true
  389. // this should succeed, since recursive implies dir=true
  390. // and recursively delete should be able to delete all
  391. // items under the given directory
  392. e, err = s.Delete("/foo", false, true)
  393. assert.Nil(t, err, "")
  394. assert.Equal(t, e.Action, "delete", "")
  395. }
  396. // Ensure that the store cannot delete a directory if both of recursive
  397. // and dir are not specified.
  398. func TestStoreDeleteDiretoryFailsIfNonRecursiveAndDir(t *testing.T) {
  399. s := newStore()
  400. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  401. e, _err := s.Delete("/foo", false, false)
  402. err := _err.(*etcdErr.Error)
  403. assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "")
  404. assert.Equal(t, err.Message, "Not a file", "")
  405. assert.Nil(t, e, "")
  406. }
  407. func TestRootRdOnly(t *testing.T) {
  408. s := newStore("/0")
  409. for _, tt := range []string{"/", "/0"} {
  410. _, err := s.Set(tt, true, "", TTLOptionSet{ExpireTime: Permanent})
  411. assert.NotNil(t, err, "")
  412. _, err = s.Delete(tt, true, true)
  413. assert.NotNil(t, err, "")
  414. _, err = s.Create(tt, true, "", false, TTLOptionSet{ExpireTime: Permanent})
  415. assert.NotNil(t, err, "")
  416. _, err = s.Update(tt, "", TTLOptionSet{ExpireTime: Permanent})
  417. assert.NotNil(t, err, "")
  418. _, err = s.CompareAndSwap(tt, "", 0, "", TTLOptionSet{ExpireTime: Permanent})
  419. assert.NotNil(t, err, "")
  420. }
  421. }
  422. func TestStoreCompareAndDeletePrevValue(t *testing.T) {
  423. s := newStore()
  424. var eidx uint64 = 2
  425. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  426. e, err := s.CompareAndDelete("/foo", "bar", 0)
  427. assert.Nil(t, err, "")
  428. assert.Equal(t, e.EtcdIndex, eidx, "")
  429. assert.Equal(t, e.Action, "compareAndDelete", "")
  430. assert.Equal(t, e.Node.Key, "/foo", "")
  431. // check prevNode
  432. assert.NotNil(t, e.PrevNode, "")
  433. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  434. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  435. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
  436. assert.Equal(t, e.PrevNode.CreatedIndex, uint64(1), "")
  437. }
  438. func TestStoreCompareAndDeletePrevValueFailsIfNotMatch(t *testing.T) {
  439. s := newStore()
  440. var eidx uint64 = 1
  441. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  442. e, _err := s.CompareAndDelete("/foo", "baz", 0)
  443. err := _err.(*etcdErr.Error)
  444. assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "")
  445. assert.Equal(t, err.Message, "Compare failed", "")
  446. assert.Nil(t, e, "")
  447. e, _ = s.Get("/foo", false, false)
  448. assert.Equal(t, e.EtcdIndex, eidx, "")
  449. assert.Equal(t, *e.Node.Value, "bar", "")
  450. }
  451. func TestStoreCompareAndDeletePrevIndex(t *testing.T) {
  452. s := newStore()
  453. var eidx uint64 = 2
  454. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  455. e, err := s.CompareAndDelete("/foo", "", 1)
  456. assert.Nil(t, err, "")
  457. assert.Equal(t, e.EtcdIndex, eidx, "")
  458. assert.Equal(t, e.Action, "compareAndDelete", "")
  459. // check prevNode
  460. assert.NotNil(t, e.PrevNode, "")
  461. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  462. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  463. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
  464. assert.Equal(t, e.PrevNode.CreatedIndex, uint64(1), "")
  465. }
  466. func TestStoreCompareAndDeletePrevIndexFailsIfNotMatch(t *testing.T) {
  467. s := newStore()
  468. var eidx uint64 = 1
  469. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  470. e, _err := s.CompareAndDelete("/foo", "", 100)
  471. assert.NotNil(t, _err, "")
  472. err := _err.(*etcdErr.Error)
  473. assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "")
  474. assert.Equal(t, err.Message, "Compare failed", "")
  475. assert.Nil(t, e, "")
  476. e, _ = s.Get("/foo", false, false)
  477. assert.Equal(t, e.EtcdIndex, eidx, "")
  478. assert.Equal(t, *e.Node.Value, "bar", "")
  479. }
  480. // Ensure that the store cannot delete a directory.
  481. func TestStoreCompareAndDeleteDiretoryFail(t *testing.T) {
  482. s := newStore()
  483. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  484. _, _err := s.CompareAndDelete("/foo", "", 0)
  485. assert.NotNil(t, _err, "")
  486. err := _err.(*etcdErr.Error)
  487. assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "")
  488. }
  489. // Ensure that the store can conditionally update a key if it has a previous value.
  490. func TestStoreCompareAndSwapPrevValue(t *testing.T) {
  491. s := newStore()
  492. var eidx uint64 = 2
  493. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  494. e, err := s.CompareAndSwap("/foo", "bar", 0, "baz", TTLOptionSet{ExpireTime: Permanent})
  495. assert.Nil(t, err, "")
  496. assert.Equal(t, e.EtcdIndex, eidx, "")
  497. assert.Equal(t, e.Action, "compareAndSwap", "")
  498. assert.Equal(t, *e.Node.Value, "baz", "")
  499. // check prevNode
  500. assert.NotNil(t, e.PrevNode, "")
  501. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  502. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  503. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
  504. assert.Equal(t, e.PrevNode.CreatedIndex, uint64(1), "")
  505. e, _ = s.Get("/foo", false, false)
  506. assert.Equal(t, *e.Node.Value, "baz", "")
  507. }
  508. // Ensure that the store cannot conditionally update a key if it has the wrong previous value.
  509. func TestStoreCompareAndSwapPrevValueFailsIfNotMatch(t *testing.T) {
  510. s := newStore()
  511. var eidx uint64 = 1
  512. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  513. e, _err := s.CompareAndSwap("/foo", "wrong_value", 0, "baz", TTLOptionSet{ExpireTime: Permanent})
  514. err := _err.(*etcdErr.Error)
  515. assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "")
  516. assert.Equal(t, err.Message, "Compare failed", "")
  517. assert.Nil(t, e, "")
  518. e, _ = s.Get("/foo", false, false)
  519. assert.Equal(t, *e.Node.Value, "bar", "")
  520. assert.Equal(t, e.EtcdIndex, eidx, "")
  521. }
  522. // Ensure that the store can conditionally update a key if it has a previous index.
  523. func TestStoreCompareAndSwapPrevIndex(t *testing.T) {
  524. s := newStore()
  525. var eidx uint64 = 2
  526. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  527. e, err := s.CompareAndSwap("/foo", "", 1, "baz", TTLOptionSet{ExpireTime: Permanent})
  528. assert.Nil(t, err, "")
  529. assert.Equal(t, e.EtcdIndex, eidx, "")
  530. assert.Equal(t, e.Action, "compareAndSwap", "")
  531. assert.Equal(t, *e.Node.Value, "baz", "")
  532. // check prevNode
  533. assert.NotNil(t, e.PrevNode, "")
  534. assert.Equal(t, e.PrevNode.Key, "/foo", "")
  535. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  536. assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "")
  537. assert.Equal(t, e.PrevNode.CreatedIndex, uint64(1), "")
  538. e, _ = s.Get("/foo", false, false)
  539. assert.Equal(t, *e.Node.Value, "baz", "")
  540. assert.Equal(t, e.EtcdIndex, eidx, "")
  541. }
  542. // Ensure that the store cannot conditionally update a key if it has the wrong previous index.
  543. func TestStoreCompareAndSwapPrevIndexFailsIfNotMatch(t *testing.T) {
  544. s := newStore()
  545. var eidx uint64 = 1
  546. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  547. e, _err := s.CompareAndSwap("/foo", "", 100, "baz", TTLOptionSet{ExpireTime: Permanent})
  548. err := _err.(*etcdErr.Error)
  549. assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "")
  550. assert.Equal(t, err.Message, "Compare failed", "")
  551. assert.Nil(t, e, "")
  552. e, _ = s.Get("/foo", false, false)
  553. assert.Equal(t, e.EtcdIndex, eidx, "")
  554. assert.Equal(t, *e.Node.Value, "bar", "")
  555. }
  556. // Ensure that the store can watch for key creation.
  557. func TestStoreWatchCreate(t *testing.T) {
  558. s := newStore()
  559. var eidx uint64 = 0
  560. w, _ := s.Watch("/foo", false, false, 0)
  561. c := w.EventChan()
  562. assert.Equal(t, w.StartIndex(), eidx, "")
  563. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  564. eidx = 1
  565. e := nbselect(c)
  566. assert.Equal(t, e.EtcdIndex, eidx, "")
  567. assert.Equal(t, e.Action, "create", "")
  568. assert.Equal(t, e.Node.Key, "/foo", "")
  569. e = nbselect(c)
  570. assert.Nil(t, e, "")
  571. }
  572. // Ensure that the store can watch for recursive key creation.
  573. func TestStoreWatchRecursiveCreate(t *testing.T) {
  574. s := newStore()
  575. var eidx uint64 = 0
  576. w, _ := s.Watch("/foo", true, false, 0)
  577. assert.Equal(t, w.StartIndex(), eidx, "")
  578. eidx = 1
  579. s.Create("/foo/bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  580. e := nbselect(w.EventChan())
  581. assert.Equal(t, e.EtcdIndex, eidx, "")
  582. assert.Equal(t, e.Action, "create", "")
  583. assert.Equal(t, e.Node.Key, "/foo/bar", "")
  584. }
  585. // Ensure that the store can watch for key updates.
  586. func TestStoreWatchUpdate(t *testing.T) {
  587. s := newStore()
  588. var eidx uint64 = 1
  589. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  590. w, _ := s.Watch("/foo", false, false, 0)
  591. assert.Equal(t, w.StartIndex(), eidx, "")
  592. eidx = 2
  593. s.Update("/foo", "baz", TTLOptionSet{ExpireTime: Permanent})
  594. e := nbselect(w.EventChan())
  595. assert.Equal(t, e.EtcdIndex, eidx, "")
  596. assert.Equal(t, e.Action, "update", "")
  597. assert.Equal(t, e.Node.Key, "/foo", "")
  598. }
  599. // Ensure that the store can watch for recursive key updates.
  600. func TestStoreWatchRecursiveUpdate(t *testing.T) {
  601. s := newStore()
  602. var eidx uint64 = 1
  603. s.Create("/foo/bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  604. w, _ := s.Watch("/foo", true, false, 0)
  605. assert.Equal(t, w.StartIndex(), eidx, "")
  606. eidx = 2
  607. s.Update("/foo/bar", "baz", TTLOptionSet{ExpireTime: Permanent})
  608. e := nbselect(w.EventChan())
  609. assert.Equal(t, e.EtcdIndex, eidx, "")
  610. assert.Equal(t, e.Action, "update", "")
  611. assert.Equal(t, e.Node.Key, "/foo/bar", "")
  612. }
  613. // Ensure that the store can watch for key deletions.
  614. func TestStoreWatchDelete(t *testing.T) {
  615. s := newStore()
  616. var eidx uint64 = 1
  617. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  618. w, _ := s.Watch("/foo", false, false, 0)
  619. assert.Equal(t, w.StartIndex(), eidx, "")
  620. eidx = 2
  621. s.Delete("/foo", false, false)
  622. e := nbselect(w.EventChan())
  623. assert.Equal(t, e.EtcdIndex, eidx, "")
  624. assert.Equal(t, e.Action, "delete", "")
  625. assert.Equal(t, e.Node.Key, "/foo", "")
  626. }
  627. // Ensure that the store can watch for recursive key deletions.
  628. func TestStoreWatchRecursiveDelete(t *testing.T) {
  629. s := newStore()
  630. var eidx uint64 = 1
  631. s.Create("/foo/bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  632. w, _ := s.Watch("/foo", true, false, 0)
  633. assert.Equal(t, w.StartIndex(), eidx, "")
  634. eidx = 2
  635. s.Delete("/foo/bar", false, false)
  636. e := nbselect(w.EventChan())
  637. assert.Equal(t, e.EtcdIndex, eidx, "")
  638. assert.Equal(t, e.Action, "delete", "")
  639. assert.Equal(t, e.Node.Key, "/foo/bar", "")
  640. }
  641. // Ensure that the store can watch for CAS updates.
  642. func TestStoreWatchCompareAndSwap(t *testing.T) {
  643. s := newStore()
  644. var eidx uint64 = 1
  645. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  646. w, _ := s.Watch("/foo", false, false, 0)
  647. assert.Equal(t, w.StartIndex(), eidx, "")
  648. eidx = 2
  649. s.CompareAndSwap("/foo", "bar", 0, "baz", TTLOptionSet{ExpireTime: Permanent})
  650. e := nbselect(w.EventChan())
  651. assert.Equal(t, e.EtcdIndex, eidx, "")
  652. assert.Equal(t, e.Action, "compareAndSwap", "")
  653. assert.Equal(t, e.Node.Key, "/foo", "")
  654. }
  655. // Ensure that the store can watch for recursive CAS updates.
  656. func TestStoreWatchRecursiveCompareAndSwap(t *testing.T) {
  657. s := newStore()
  658. var eidx uint64 = 1
  659. s.Create("/foo/bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  660. w, _ := s.Watch("/foo", true, false, 0)
  661. assert.Equal(t, w.StartIndex(), eidx, "")
  662. eidx = 2
  663. s.CompareAndSwap("/foo/bar", "baz", 0, "bat", TTLOptionSet{ExpireTime: Permanent})
  664. e := nbselect(w.EventChan())
  665. assert.Equal(t, e.EtcdIndex, eidx, "")
  666. assert.Equal(t, e.Action, "compareAndSwap", "")
  667. assert.Equal(t, e.Node.Key, "/foo/bar", "")
  668. }
  669. // Ensure that the store can watch for key expiration.
  670. func TestStoreWatchExpire(t *testing.T) {
  671. s := newStore()
  672. fc := newFakeClock()
  673. s.clock = fc
  674. var eidx uint64 = 2
  675. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  676. s.Create("/foofoo", false, "barbarbar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  677. w, _ := s.Watch("/", true, false, 0)
  678. assert.Equal(t, w.StartIndex(), eidx, "")
  679. c := w.EventChan()
  680. e := nbselect(c)
  681. assert.Nil(t, e, "")
  682. fc.Advance(600 * time.Millisecond)
  683. s.DeleteExpiredKeys(fc.Now())
  684. eidx = 3
  685. e = nbselect(c)
  686. assert.Equal(t, e.EtcdIndex, eidx, "")
  687. assert.Equal(t, e.Action, "expire", "")
  688. assert.Equal(t, e.Node.Key, "/foo", "")
  689. w, _ = s.Watch("/", true, false, 4)
  690. eidx = 4
  691. assert.Equal(t, w.StartIndex(), eidx, "")
  692. e = nbselect(w.EventChan())
  693. assert.Equal(t, e.EtcdIndex, eidx, "")
  694. assert.Equal(t, e.Action, "expire", "")
  695. assert.Equal(t, e.Node.Key, "/foofoo", "")
  696. }
  697. // Ensure that the store can watch for key expiration when refreshing.
  698. func TestStoreWatchExpireRefresh(t *testing.T) {
  699. s := newStore()
  700. fc := newFakeClock()
  701. s.clock = fc
  702. var eidx uint64 = 2
  703. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  704. s.Create("/foofoo", false, "barbarbar", false, TTLOptionSet{ExpireTime: fc.Now().Add(1200 * time.Millisecond), Refresh: true})
  705. // Make sure we set watch updates when Refresh is true for newly created keys
  706. w, _ := s.Watch("/", true, false, 0)
  707. assert.Equal(t, w.StartIndex(), eidx, "")
  708. c := w.EventChan()
  709. e := nbselect(c)
  710. assert.Nil(t, e, "")
  711. fc.Advance(600 * time.Millisecond)
  712. s.DeleteExpiredKeys(fc.Now())
  713. eidx = 3
  714. e = nbselect(c)
  715. assert.Equal(t, e.EtcdIndex, eidx, "")
  716. assert.Equal(t, e.Action, "expire", "")
  717. assert.Equal(t, e.Node.Key, "/foo", "")
  718. s.Update("/foofoo", "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  719. w, _ = s.Watch("/", true, false, 4)
  720. fc.Advance(700 * time.Millisecond)
  721. s.DeleteExpiredKeys(fc.Now())
  722. eidx = 5 // We should skip 4 because a TTL update should occur with no watch notification if set `TTLOptionSet.Refresh` to true
  723. assert.Equal(t, w.StartIndex(), eidx-1, "")
  724. e = nbselect(w.EventChan())
  725. assert.Equal(t, e.EtcdIndex, eidx, "")
  726. assert.Equal(t, e.Action, "expire", "")
  727. assert.Equal(t, e.Node.Key, "/foofoo", "")
  728. }
  729. // Ensure that the store can watch for key expiration when refreshing with an empty value.
  730. func TestStoreWatchExpireEmptyRefresh(t *testing.T) {
  731. s := newStore()
  732. fc := newFakeClock()
  733. s.clock = fc
  734. var eidx uint64 = 1
  735. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  736. // Should be no-op
  737. fc.Advance(200 * time.Millisecond)
  738. s.DeleteExpiredKeys(fc.Now())
  739. s.Update("/foo", "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  740. w, _ := s.Watch("/", true, false, 2)
  741. fc.Advance(700 * time.Millisecond)
  742. s.DeleteExpiredKeys(fc.Now())
  743. eidx = 3 // We should skip 2 because a TTL update should occur with no watch notification if set `TTLOptionSet.Refresh` to true
  744. assert.Equal(t, w.StartIndex(), eidx-1, "")
  745. e := nbselect(w.EventChan())
  746. assert.Equal(t, e.EtcdIndex, eidx, "")
  747. assert.Equal(t, e.Action, "expire", "")
  748. assert.Equal(t, e.Node.Key, "/foo", "")
  749. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  750. }
  751. // Update TTL of a key (set TTLOptionSet.Refresh to false) and send notification
  752. func TestStoreWatchNoRefresh(t *testing.T) {
  753. s := newStore()
  754. fc := newFakeClock()
  755. s.clock = fc
  756. var eidx uint64 = 1
  757. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  758. // Should be no-op
  759. fc.Advance(200 * time.Millisecond)
  760. s.DeleteExpiredKeys(fc.Now())
  761. // Update key's TTL with setting `TTLOptionSet.Refresh` to false will cause an update event
  762. s.Update("/foo", "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: false})
  763. w, _ := s.Watch("/", true, false, 2)
  764. fc.Advance(700 * time.Millisecond)
  765. s.DeleteExpiredKeys(fc.Now())
  766. eidx = 2
  767. assert.Equal(t, w.StartIndex(), eidx, "")
  768. e := nbselect(w.EventChan())
  769. assert.Equal(t, e.EtcdIndex, eidx, "")
  770. assert.Equal(t, e.Action, "update", "")
  771. assert.Equal(t, e.Node.Key, "/foo", "")
  772. assert.Equal(t, *e.PrevNode.Value, "bar", "")
  773. }
  774. // Ensure that the store can update the TTL on a value with refresh.
  775. func TestStoreRefresh(t *testing.T) {
  776. s := newStore()
  777. fc := newFakeClock()
  778. s.clock = fc
  779. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  780. s.Create("/bar", true, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  781. _, err := s.Update("/foo", "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  782. assert.Nil(t, err, "")
  783. _, err = s.Set("/foo", false, "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  784. assert.Nil(t, err, "")
  785. _, err = s.Update("/bar", "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  786. assert.Nil(t, err, "")
  787. _, err = s.CompareAndSwap("/foo", "bar", 0, "", TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond), Refresh: true})
  788. assert.Nil(t, err, "")
  789. }
  790. // Ensure that the store can watch in streaming mode.
  791. func TestStoreWatchStream(t *testing.T) {
  792. s := newStore()
  793. var eidx uint64 = 1
  794. w, _ := s.Watch("/foo", false, true, 0)
  795. // first modification
  796. s.Create("/foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  797. e := nbselect(w.EventChan())
  798. assert.Equal(t, e.EtcdIndex, eidx, "")
  799. assert.Equal(t, e.Action, "create", "")
  800. assert.Equal(t, e.Node.Key, "/foo", "")
  801. assert.Equal(t, *e.Node.Value, "bar", "")
  802. e = nbselect(w.EventChan())
  803. assert.Nil(t, e, "")
  804. // second modification
  805. eidx = 2
  806. s.Update("/foo", "baz", TTLOptionSet{ExpireTime: Permanent})
  807. e = nbselect(w.EventChan())
  808. assert.Equal(t, e.EtcdIndex, eidx, "")
  809. assert.Equal(t, e.Action, "update", "")
  810. assert.Equal(t, e.Node.Key, "/foo", "")
  811. assert.Equal(t, *e.Node.Value, "baz", "")
  812. e = nbselect(w.EventChan())
  813. assert.Nil(t, e, "")
  814. }
  815. // Ensure that the store can recover from a previously saved state.
  816. func TestStoreRecover(t *testing.T) {
  817. s := newStore()
  818. var eidx uint64 = 4
  819. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  820. s.Create("/foo/x", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  821. s.Update("/foo/x", "barbar", TTLOptionSet{ExpireTime: Permanent})
  822. s.Create("/foo/y", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  823. b, err := s.Save()
  824. s2 := newStore()
  825. s2.Recovery(b)
  826. e, err := s.Get("/foo/x", false, false)
  827. assert.Equal(t, e.Node.CreatedIndex, uint64(2), "")
  828. assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "")
  829. assert.Equal(t, e.EtcdIndex, eidx, "")
  830. assert.Nil(t, err, "")
  831. assert.Equal(t, *e.Node.Value, "barbar", "")
  832. e, err = s.Get("/foo/y", false, false)
  833. assert.Equal(t, e.EtcdIndex, eidx, "")
  834. assert.Nil(t, err, "")
  835. assert.Equal(t, *e.Node.Value, "baz", "")
  836. }
  837. // Ensure that the store can recover from a previously saved state that includes an expiring key.
  838. func TestStoreRecoverWithExpiration(t *testing.T) {
  839. s := newStore()
  840. s.clock = newFakeClock()
  841. fc := newFakeClock()
  842. var eidx uint64 = 4
  843. s.Create("/foo", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  844. s.Create("/foo/x", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  845. s.Create("/foo/y", false, "baz", false, TTLOptionSet{ExpireTime: fc.Now().Add(5 * time.Millisecond)})
  846. b, err := s.Save()
  847. time.Sleep(10 * time.Millisecond)
  848. s2 := newStore()
  849. s2.clock = fc
  850. s2.Recovery(b)
  851. fc.Advance(600 * time.Millisecond)
  852. s.DeleteExpiredKeys(fc.Now())
  853. e, err := s.Get("/foo/x", false, false)
  854. assert.Nil(t, err, "")
  855. assert.Equal(t, e.EtcdIndex, eidx, "")
  856. assert.Equal(t, *e.Node.Value, "bar", "")
  857. e, err = s.Get("/foo/y", false, false)
  858. assert.NotNil(t, err, "")
  859. assert.Nil(t, e, "")
  860. }
  861. // Ensure that the store can watch for hidden keys as long as it's an exact path match.
  862. func TestStoreWatchCreateWithHiddenKey(t *testing.T) {
  863. s := newStore()
  864. var eidx uint64 = 1
  865. w, _ := s.Watch("/_foo", false, false, 0)
  866. s.Create("/_foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  867. e := nbselect(w.EventChan())
  868. assert.Equal(t, e.EtcdIndex, eidx, "")
  869. assert.Equal(t, e.Action, "create", "")
  870. assert.Equal(t, e.Node.Key, "/_foo", "")
  871. e = nbselect(w.EventChan())
  872. assert.Nil(t, e, "")
  873. }
  874. // Ensure that the store doesn't see hidden key creates without an exact path match in recursive mode.
  875. func TestStoreWatchRecursiveCreateWithHiddenKey(t *testing.T) {
  876. s := newStore()
  877. w, _ := s.Watch("/foo", true, false, 0)
  878. s.Create("/foo/_bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  879. e := nbselect(w.EventChan())
  880. assert.Nil(t, e, "")
  881. w, _ = s.Watch("/foo", true, false, 0)
  882. s.Create("/foo/_baz", true, "", false, TTLOptionSet{ExpireTime: Permanent})
  883. e = nbselect(w.EventChan())
  884. assert.Nil(t, e, "")
  885. s.Create("/foo/_baz/quux", false, "quux", false, TTLOptionSet{ExpireTime: Permanent})
  886. e = nbselect(w.EventChan())
  887. assert.Nil(t, e, "")
  888. }
  889. // Ensure that the store doesn't see hidden key updates.
  890. func TestStoreWatchUpdateWithHiddenKey(t *testing.T) {
  891. s := newStore()
  892. s.Create("/_foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  893. w, _ := s.Watch("/_foo", false, false, 0)
  894. s.Update("/_foo", "baz", TTLOptionSet{ExpireTime: Permanent})
  895. e := nbselect(w.EventChan())
  896. assert.Equal(t, e.Action, "update", "")
  897. assert.Equal(t, e.Node.Key, "/_foo", "")
  898. e = nbselect(w.EventChan())
  899. assert.Nil(t, e, "")
  900. }
  901. // Ensure that the store doesn't see hidden key updates without an exact path match in recursive mode.
  902. func TestStoreWatchRecursiveUpdateWithHiddenKey(t *testing.T) {
  903. s := newStore()
  904. s.Create("/foo/_bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  905. w, _ := s.Watch("/foo", true, false, 0)
  906. s.Update("/foo/_bar", "baz", TTLOptionSet{ExpireTime: Permanent})
  907. e := nbselect(w.EventChan())
  908. assert.Nil(t, e, "")
  909. }
  910. // Ensure that the store can watch for key deletions.
  911. func TestStoreWatchDeleteWithHiddenKey(t *testing.T) {
  912. s := newStore()
  913. var eidx uint64 = 2
  914. s.Create("/_foo", false, "bar", false, TTLOptionSet{ExpireTime: Permanent})
  915. w, _ := s.Watch("/_foo", false, false, 0)
  916. s.Delete("/_foo", false, false)
  917. e := nbselect(w.EventChan())
  918. assert.Equal(t, e.EtcdIndex, eidx, "")
  919. assert.Equal(t, e.Action, "delete", "")
  920. assert.Equal(t, e.Node.Key, "/_foo", "")
  921. e = nbselect(w.EventChan())
  922. assert.Nil(t, e, "")
  923. }
  924. // Ensure that the store doesn't see hidden key deletes without an exact path match in recursive mode.
  925. func TestStoreWatchRecursiveDeleteWithHiddenKey(t *testing.T) {
  926. s := newStore()
  927. s.Create("/foo/_bar", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  928. w, _ := s.Watch("/foo", true, false, 0)
  929. s.Delete("/foo/_bar", false, false)
  930. e := nbselect(w.EventChan())
  931. assert.Nil(t, e, "")
  932. }
  933. // Ensure that the store doesn't see expirations of hidden keys.
  934. func TestStoreWatchExpireWithHiddenKey(t *testing.T) {
  935. s := newStore()
  936. fc := newFakeClock()
  937. s.clock = fc
  938. s.Create("/_foo", false, "bar", false, TTLOptionSet{ExpireTime: fc.Now().Add(500 * time.Millisecond)})
  939. s.Create("/foofoo", false, "barbarbar", false, TTLOptionSet{ExpireTime: fc.Now().Add(1000 * time.Millisecond)})
  940. w, _ := s.Watch("/", true, false, 0)
  941. c := w.EventChan()
  942. e := nbselect(c)
  943. assert.Nil(t, e, "")
  944. fc.Advance(600 * time.Millisecond)
  945. s.DeleteExpiredKeys(fc.Now())
  946. e = nbselect(c)
  947. assert.Nil(t, e, "")
  948. fc.Advance(600 * time.Millisecond)
  949. s.DeleteExpiredKeys(fc.Now())
  950. e = nbselect(c)
  951. assert.Equal(t, e.Action, "expire", "")
  952. assert.Equal(t, e.Node.Key, "/foofoo", "")
  953. }
  954. // Ensure that the store does see hidden key creates if watching deeper than a hidden key in recursive mode.
  955. func TestStoreWatchRecursiveCreateDeeperThanHiddenKey(t *testing.T) {
  956. s := newStore()
  957. var eidx uint64 = 1
  958. w, _ := s.Watch("/_foo/bar", true, false, 0)
  959. s.Create("/_foo/bar/baz", false, "baz", false, TTLOptionSet{ExpireTime: Permanent})
  960. e := nbselect(w.EventChan())
  961. assert.NotNil(t, e, "")
  962. assert.Equal(t, e.EtcdIndex, eidx, "")
  963. assert.Equal(t, e.Action, "create", "")
  964. assert.Equal(t, e.Node.Key, "/_foo/bar/baz", "")
  965. }
  966. // Ensure that slow consumers are handled properly.
  967. //
  968. // Since Watcher.EventChan() has a buffer of size 100 we can only queue 100
  969. // event per watcher. If the consumer cannot consume the event on time and
  970. // another event arrives, the channel is closed and event is discarded.
  971. // This test ensures that after closing the channel, the store can continue
  972. // to operate correctly.
  973. func TestStoreWatchSlowConsumer(t *testing.T) {
  974. s := newStore()
  975. s.Watch("/foo", true, true, 0) // stream must be true
  976. // Fill watch channel with 100 events
  977. for i := 1; i <= 100; i++ {
  978. s.Set("/foo", false, string(i), TTLOptionSet{ExpireTime: Permanent}) // ok
  979. }
  980. assert.Equal(t, s.WatcherHub.count, int64(1), "")
  981. s.Set("/foo", false, "101", TTLOptionSet{ExpireTime: Permanent}) // ok
  982. // remove watcher
  983. assert.Equal(t, s.WatcherHub.count, int64(0), "")
  984. s.Set("/foo", false, "102", TTLOptionSet{ExpireTime: Permanent}) // must not panic
  985. }
  986. // Performs a non-blocking select on an event channel.
  987. func nbselect(c <-chan *Event) *Event {
  988. select {
  989. case e := <-c:
  990. return e
  991. default:
  992. return nil
  993. }
  994. }
  995. // newFakeClock creates a new FakeClock that has been advanced to at least minExpireTime
  996. func newFakeClock() clockwork.FakeClock {
  997. fc := clockwork.NewFakeClock()
  998. for minExpireTime.After(fc.Now()) {
  999. fc.Advance((0x1 << 62) * time.Nanosecond)
  1000. }
  1001. return fc
  1002. }