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
64		// coverage tests get extra arguments:
65		// ./bin/etcdctl_test -test.coverprofile=e2e.1525392462795198897.coverprofile -test.outputdir=../..
66		// do not test watch exec commands
67
68		{ // watch 3 keys by prefix
69			puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
70			args: []string{"key", "--rev", "1", "--prefix"},
71			wkv:  []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}},
72		},
73		{ // watch 3 keys by prefix, with env
74			puts:   []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
75			envKey: "key",
76			args:   []string{"--rev", "1", "--prefix"},
77			wkv:    []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}},
78		},
79		{ // watch by revision
80			puts: []kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}},
81			args: []string{"etcd", "--rev", "2"},
82			wkv:  []kvExec{{key: "etcd", val: "revision_2"}, {key: "etcd", val: "revision_3"}},
83		},
84		{ // watch 3 keys by range
85			puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
86			args: []string{"key", "key3", "--rev", "1"},
87			wkv:  []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
88		},
89		{ // watch 3 keys by range, with env
90			puts:     []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
91			envKey:   "key",
92			envRange: "key3",
93			args:     []string{"--rev", "1"},
94			wkv:      []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
95		},
96	}
97
98	for i, tt := range tests {
99		donec := make(chan struct{})
100		go func(i int, puts []kv) {
101			for j := range puts {
102				if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil {
103					cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err)
104				}
105			}
106			close(donec)
107		}(i, tt.puts)
108
109		unsetEnv := func() {}
110		if tt.envKey != "" || tt.envRange != "" {
111			if tt.envKey != "" {
112				os.Setenv("ETCDCTL_WATCH_KEY", tt.envKey)
113				unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_KEY") }
114			}
115			if tt.envRange != "" {
116				os.Setenv("ETCDCTL_WATCH_RANGE_END", tt.envRange)
117				unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_RANGE_END") }
118			}
119			if tt.envKey != "" && tt.envRange != "" {
120				unsetEnv = func() {
121					os.Unsetenv("ETCDCTL_WATCH_KEY")
122					os.Unsetenv("ETCDCTL_WATCH_RANGE_END")
123				}
124			}
125		}
126		if err := ctlV3Watch(cx, tt.args, tt.wkv...); err != nil {
127			if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
128				cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err)
129			}
130		}
131		unsetEnv()
132		<-donec
133	}
134}
135