ctl_v3_watch_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // Copyright 2016 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 e2e
  15. import (
  16. "os"
  17. "strings"
  18. "testing"
  19. )
  20. func TestCtlV3Watch(t *testing.T) { testCtl(t, watchTest) }
  21. func TestCtlV3WatchNoTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configNoTLS)) }
  22. func TestCtlV3WatchClientTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configClientTLS)) }
  23. func TestCtlV3WatchPeerTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configPeerTLS)) }
  24. func TestCtlV3WatchTimeout(t *testing.T) { testCtl(t, watchTest, withDialTimeout(0)) }
  25. func TestCtlV3WatchInteractive(t *testing.T) {
  26. testCtl(t, watchTest, withInteractive())
  27. }
  28. func TestCtlV3WatchInteractiveNoTLS(t *testing.T) {
  29. testCtl(t, watchTest, withInteractive(), withCfg(configNoTLS))
  30. }
  31. func TestCtlV3WatchInteractiveClientTLS(t *testing.T) {
  32. testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS))
  33. }
  34. func TestCtlV3WatchInteractivePeerTLS(t *testing.T) {
  35. testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS))
  36. }
  37. type kvExec struct {
  38. key, val string
  39. execOutput string
  40. }
  41. func watchTest(cx ctlCtx) {
  42. tests := []struct {
  43. puts []kv
  44. envKey string
  45. envRange string
  46. args []string
  47. wkv []kvExec
  48. }{
  49. { // watch 1 key
  50. puts: []kv{{"sample", "value"}},
  51. args: []string{"sample", "--rev", "1"},
  52. wkv: []kvExec{{key: "sample", val: "value"}},
  53. },
  54. { // watch 1 key with env
  55. puts: []kv{{"sample", "value"}},
  56. envKey: "sample",
  57. args: []string{"--rev", "1"},
  58. wkv: []kvExec{{key: "sample", val: "value"}},
  59. },
  60. { // watch 1 key with "echo watch event received"
  61. puts: []kv{{"sample", "value"}},
  62. args: []string{"sample", "--rev", "1", "--", "echo", "watch event received"},
  63. wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
  64. },
  65. { // watch 1 key with ${ETCD_WATCH_VALUE}
  66. puts: []kv{{"sample", "value"}},
  67. args: []string{"sample", "--rev", "1", "--", "env"},
  68. wkv: []kvExec{{key: "sample", val: "value", execOutput: `ETCD_WATCH_VALUE="value"`}},
  69. },
  70. { // watch 1 key with "echo watch event received", with env
  71. puts: []kv{{"sample", "value"}},
  72. envKey: "sample",
  73. args: []string{"--rev", "1", "--", "echo", "watch event received"},
  74. wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
  75. },
  76. { // watch 1 key with "echo watch event received"
  77. puts: []kv{{"sample", "value"}},
  78. args: []string{"--rev", "1", "sample", "--", "echo", "watch event received"},
  79. wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
  80. },
  81. { // watch 1 key with "echo \"Hello World!\""
  82. puts: []kv{{"sample", "value"}},
  83. args: []string{"--rev", "1", "sample", "--", "echo", "\"Hello World!\""},
  84. wkv: []kvExec{{key: "sample", val: "value", execOutput: "Hello World!"}},
  85. },
  86. { // watch 1 key with "echo watch event received"
  87. puts: []kv{{"sample", "value"}},
  88. args: []string{"sample", "samplx", "--rev", "1", "--", "echo", "watch event received"},
  89. wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
  90. },
  91. { // watch 1 key with "echo watch event received"
  92. puts: []kv{{"sample", "value"}},
  93. envKey: "sample",
  94. envRange: "samplx",
  95. args: []string{"--rev", "1", "--", "echo", "watch event received"},
  96. wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
  97. },
  98. { // watch 1 key with "echo watch event received"
  99. puts: []kv{{"sample", "value"}},
  100. args: []string{"sample", "--rev", "1", "samplx", "--", "echo", "watch event received"},
  101. wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
  102. },
  103. { // watch 3 keys by prefix
  104. puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
  105. args: []string{"key", "--rev", "1", "--prefix"},
  106. wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}},
  107. },
  108. { // watch 3 keys by prefix, with env
  109. puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
  110. envKey: "key",
  111. args: []string{"--rev", "1", "--prefix"},
  112. wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}},
  113. },
  114. { // watch by revision
  115. puts: []kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}},
  116. args: []string{"etcd", "--rev", "2"},
  117. wkv: []kvExec{{key: "etcd", val: "revision_2"}, {key: "etcd", val: "revision_3"}},
  118. },
  119. { // watch 3 keys by range
  120. puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
  121. args: []string{"key", "key3", "--rev", "1"},
  122. wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
  123. },
  124. { // watch 3 keys by range, with env
  125. puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
  126. envKey: "key",
  127. envRange: "key3",
  128. args: []string{"--rev", "1"},
  129. wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
  130. },
  131. }
  132. for i, tt := range tests {
  133. donec := make(chan struct{})
  134. go func(i int, puts []kv) {
  135. for j := range puts {
  136. if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil {
  137. cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err)
  138. }
  139. }
  140. close(donec)
  141. }(i, tt.puts)
  142. unsetEnv := func() {}
  143. if tt.envKey != "" || tt.envRange != "" {
  144. if tt.envKey != "" {
  145. os.Setenv("ETCDCTL_WATCH_KEY", tt.envKey)
  146. unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_KEY") }
  147. }
  148. if tt.envRange != "" {
  149. os.Setenv("ETCDCTL_WATCH_RANGE_END", tt.envRange)
  150. unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_RANGE_END") }
  151. }
  152. if tt.envKey != "" && tt.envRange != "" {
  153. unsetEnv = func() {
  154. os.Unsetenv("ETCDCTL_WATCH_KEY")
  155. os.Unsetenv("ETCDCTL_WATCH_RANGE_END")
  156. }
  157. }
  158. }
  159. if err := ctlV3Watch(cx, tt.args, tt.wkv...); err != nil {
  160. if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
  161. cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err)
  162. }
  163. }
  164. unsetEnv()
  165. <-donec
  166. }
  167. }
  168. func setupWatchArgs(cx ctlCtx, args []string) []string {
  169. cmdArgs := append(cx.PrefixArgs(), "watch")
  170. if cx.interactive {
  171. cmdArgs = append(cmdArgs, "--interactive")
  172. } else {
  173. cmdArgs = append(cmdArgs, args...)
  174. }
  175. return cmdArgs
  176. }
  177. func ctlV3Watch(cx ctlCtx, args []string, kvs ...kvExec) error {
  178. cmdArgs := setupWatchArgs(cx, args)
  179. proc, err := spawnCmd(cmdArgs)
  180. if err != nil {
  181. return err
  182. }
  183. if cx.interactive {
  184. wl := strings.Join(append([]string{"watch"}, args...), " ") + "\r"
  185. if err = proc.Send(wl); err != nil {
  186. return err
  187. }
  188. }
  189. for _, elem := range kvs {
  190. if _, err = proc.Expect(elem.key); err != nil {
  191. return err
  192. }
  193. if _, err = proc.Expect(elem.val); err != nil {
  194. return err
  195. }
  196. if elem.execOutput != "" {
  197. if _, err = proc.Expect(elem.execOutput); err != nil {
  198. return err
  199. }
  200. }
  201. }
  202. return proc.Stop()
  203. }
  204. func ctlV3WatchFailPerm(cx ctlCtx, args []string) error {
  205. cmdArgs := setupWatchArgs(cx, args)
  206. proc, err := spawnCmd(cmdArgs)
  207. if err != nil {
  208. return err
  209. }
  210. if cx.interactive {
  211. wl := strings.Join(append([]string{"watch"}, args...), " ") + "\r"
  212. if err = proc.Send(wl); err != nil {
  213. return err
  214. }
  215. }
  216. // TODO(mitake): after printing accurate error message that includes
  217. // "permission denied", the above string argument of proc.Expect()
  218. // should be updated.
  219. _, err = proc.Expect("watch is canceled by the server")
  220. if err != nil {
  221. return err
  222. }
  223. return proc.Close()
  224. }