1// Copyright 2018 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
15// +build !cov
16
17package e2e
18
19import (
20	"os"
21	"testing"
22)
23
24func TestCtlV3Watch(t *testing.T)          { testCtl(t, watchTest) }
25func TestCtlV3WatchNoTLS(t *testing.T)     { testCtl(t, watchTest, withCfg(configNoTLS)) }
26func TestCtlV3WatchClientTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configClientTLS)) }
27func TestCtlV3WatchPeerTLS(t *testing.T)   { testCtl(t, watchTest, withCfg(configPeerTLS)) }
28func TestCtlV3WatchTimeout(t *testing.T)   { testCtl(t, watchTest, withDialTimeout(0)) }
29
30func TestCtlV3WatchInteractive(t *testing.T) {
31	testCtl(t, watchTest, withInteractive())
32}
33func TestCtlV3WatchInteractiveNoTLS(t *testing.T) {
34	testCtl(t, watchTest, withInteractive(), withCfg(configNoTLS))
35}
36func TestCtlV3WatchInteractiveClientTLS(t *testing.T) {
37	testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS))
38}
39func TestCtlV3WatchInteractivePeerTLS(t *testing.T) {
40	testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS))
41}
42
43func watchTest(cx ctlCtx) {
44	tests := []struct {
45		puts     []kv
46		envKey   string
47		envRange string
48		args     []string
49
50		wkv []kvExec
51	}{
52		{ // watch 1 key
53			puts: []kv{{"sample", "value"}},
54			args: []string{"sample", "--rev", "1"},
55			wkv:  []kvExec{{key: "sample", val: "value"}},
56		},
57		{ // watch 1 key with env
58			puts:   []kv{{"sample", "value"}},
59			envKey: "sample",
60			args:   []string{"--rev", "1"},
61			wkv:    []kvExec{{key: "sample", val: "value"}},
62		},
63		{ // watch 1 key with ${ETCD_WATCH_VALUE}
64			puts: []kv{{"sample", "value"}},
65			args: []string{"sample", "--rev", "1", "--", "env"},
66			wkv:  []kvExec{{key: "sample", val: "value", execOutput: `ETCD_WATCH_VALUE="value"`}},
67		},
68		{ // watch 1 key with "echo watch event received", with env
69			puts:   []kv{{"sample", "value"}},
70			envKey: "sample",
71			args:   []string{"--rev", "1", "--", "echo", "watch event received"},
72			wkv:    []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
73		},
74		{ // watch 1 key with "echo watch event received"
75			puts: []kv{{"sample", "value"}},
76			args: []string{"--rev", "1", "sample", "--", "echo", "watch event received"},
77			wkv:  []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
78		},
79		{ // watch 1 key with "echo \"Hello World!\""
80			puts: []kv{{"sample", "value"}},
81			args: []string{"--rev", "1", "sample", "--", "echo", "\"Hello World!\""},
82			wkv:  []kvExec{{key: "sample", val: "value", execOutput: "Hello World!"}},
83		},
84		{ // watch 1 key with "echo watch event received"
85			puts: []kv{{"sample", "value"}},
86			args: []string{"sample", "samplx", "--rev", "1", "--", "echo", "watch event received"},
87			wkv:  []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
88		},
89		{ // watch 1 key with "echo watch event received"
90			puts:     []kv{{"sample", "value"}},
91			envKey:   "sample",
92			envRange: "samplx",
93			args:     []string{"--rev", "1", "--", "echo", "watch event received"},
94			wkv:      []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
95		},
96		{ // watch 1 key with "echo watch event received"
97			puts: []kv{{"sample", "value"}},
98			args: []string{"sample", "--rev", "1", "samplx", "--", "echo", "watch event received"},
99			wkv:  []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}},
100		},
101		{ // watch 3 keys by prefix
102			puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
103			args: []string{"key", "--rev", "1", "--prefix"},
104			wkv:  []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}},
105		},
106		{ // watch 3 keys by prefix, with env
107			puts:   []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
108			envKey: "key",
109			args:   []string{"--rev", "1", "--prefix"},
110			wkv:    []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}},
111		},
112		{ // watch by revision
113			puts: []kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}},
114			args: []string{"etcd", "--rev", "2"},
115			wkv:  []kvExec{{key: "etcd", val: "revision_2"}, {key: "etcd", val: "revision_3"}},
116		},
117		{ // watch 3 keys by range
118			puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
119			args: []string{"key", "key3", "--rev", "1"},
120			wkv:  []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
121		},
122		{ // watch 3 keys by range, with env
123			puts:     []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
124			envKey:   "key",
125			envRange: "key3",
126			args:     []string{"--rev", "1"},
127			wkv:      []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
128		},
129	}
130
131	for i, tt := range tests {
132		donec := make(chan struct{})
133		go func(i int, puts []kv) {
134			for j := range puts {
135				if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil {
136					cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err)
137				}
138			}
139			close(donec)
140		}(i, tt.puts)
141
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