Skip to content

Commit 7a1b8ea

Browse files
author
jennybuckley
committedMay 30, 2018
Promote watch e2e test to conformance
1 parent 0c837a3 commit 7a1b8ea

File tree

2 files changed

+254
-80
lines changed

2 files changed

+254
-80
lines changed
 

‎test/conformance/testdata/conformance.txt

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ test/e2e/apimachinery/garbage_collector.go: "should orphan RS created by deploym
66
test/e2e/apimachinery/garbage_collector.go: "should keep the rc around until all its pods are deleted if the deleteOptions says so"
77
test/e2e/apimachinery/garbage_collector.go: "should not delete dependents that have both valid owner and owner that's waiting for dependents to be deleted"
88
test/e2e/apimachinery/garbage_collector.go: "should not be blocked by dependency circle"
9+
test/e2e/apimachinery/watch.go: "should observe add, update, and delete watch notifications on configmaps"
10+
test/e2e/apimachinery/watch.go: "should be able to start watching from a specific resource version"
11+
test/e2e/apimachinery/watch.go: "should be able to restart watching from the last resource version observed by the previous watch"
12+
test/e2e/apimachinery/watch.go: "should observe an object deletion if it stops meeting the requirements of the selector"
913
test/e2e/apps/daemon_set.go: "should run and stop simple daemon"
1014
test/e2e/apps/daemon_set.go: "should run and stop complex daemon"
1115
test/e2e/apps/daemon_set.go: "should retry creating failed daemon pods"

‎test/e2e/apimachinery/watch.go

+250-80
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ import (
2121

2222
"k8s.io/api/core/v1"
2323
apiequality "k8s.io/apimachinery/pkg/api/equality"
24-
"k8s.io/apimachinery/pkg/api/errors"
2524
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2625
"k8s.io/apimachinery/pkg/runtime"
27-
"k8s.io/apimachinery/pkg/util/wait"
2826
"k8s.io/apimachinery/pkg/watch"
2927
"k8s.io/kubernetes/test/e2e/framework"
3028

@@ -33,158 +31,330 @@ import (
3331
)
3432

3533
const (
36-
watchPodLabelKey = "watch-this-pod"
37-
watchPodLabelValueA = "AAA"
38-
watchPodLabelValueB = "BBB"
34+
watchConfigMapLabelKey = "watch-this-configmap"
35+
36+
multipleWatchersLabelValueA = "multiple-watchers-A"
37+
multipleWatchersLabelValueB = "multiple-watchers-B"
38+
fromResourceVersionLabelValue = "from-resource-version"
39+
watchRestartedLabelValue = "watch-closed-and-restarted"
40+
toBeChangedLabelValue = "label-changed-and-restored"
3941
)
4042

4143
var _ = SIGDescribe("Watchers", func() {
4244
f := framework.NewDefaultFramework("watch")
4345

44-
It("should observe add, update, and delete events on pods", func() {
46+
/*
47+
Testname: watch-configmaps-with-multiple-watchers
48+
Description: Ensure that multiple watchers are able to receive all add,
49+
update, and delete notifications on configmaps that match a label selector and do
50+
not receive notifications for configmaps which do not match that label selector.
51+
*/
52+
framework.ConformanceIt("should observe add, update, and delete watch notifications on configmaps", func() {
4553
c := f.ClientSet
4654
ns := f.Namespace.Name
4755

48-
By("creating multiple similar watches on pods")
49-
watchA, err := watchPodsWithLabels(f, watchPodLabelValueA)
56+
By("creating a watch on configmaps with label A")
57+
watchA, err := watchConfigMaps(f, "", multipleWatchersLabelValueA)
5058
Expect(err).NotTo(HaveOccurred())
5159

52-
watchB, err := watchPodsWithLabels(f, watchPodLabelValueB)
60+
By("creating a watch on configmaps with label B")
61+
watchB, err := watchConfigMaps(f, "", multipleWatchersLabelValueB)
5362
Expect(err).NotTo(HaveOccurred())
5463

55-
watchAB, err := watchPodsWithLabels(f, watchPodLabelValueA, watchPodLabelValueB)
64+
By("creating a watch on configmaps with label A or B")
65+
watchAB, err := watchConfigMaps(f, "", multipleWatchersLabelValueA, multipleWatchersLabelValueB)
5666
Expect(err).NotTo(HaveOccurred())
5767

58-
By("creating, modifying, and deleting pods")
59-
testPodA := &v1.Pod{
68+
testConfigMapA := &v1.ConfigMap{
6069
ObjectMeta: metav1.ObjectMeta{
61-
Name: "e2e-watch-test-pod-a",
70+
Name: "e2e-watch-test-configmap-a",
6271
Labels: map[string]string{
63-
watchPodLabelKey: watchPodLabelValueA,
64-
},
65-
},
66-
Spec: v1.PodSpec{
67-
Containers: []v1.Container{
68-
{
69-
Name: "example",
70-
Image: framework.GetPauseImageName(c),
71-
},
72+
watchConfigMapLabelKey: multipleWatchersLabelValueA,
7273
},
7374
},
7475
}
75-
testPodB := &v1.Pod{
76+
testConfigMapB := &v1.ConfigMap{
7677
ObjectMeta: metav1.ObjectMeta{
77-
Name: "e2e-watch-test-pod-b",
78+
Name: "e2e-watch-test-configmap-b",
7879
Labels: map[string]string{
79-
watchPodLabelKey: watchPodLabelValueB,
80-
},
81-
},
82-
Spec: v1.PodSpec{
83-
Containers: []v1.Container{
84-
{
85-
Name: "example",
86-
Image: framework.GetPauseImageName(c),
87-
},
80+
watchConfigMapLabelKey: multipleWatchersLabelValueB,
8881
},
8982
},
9083
}
91-
testPodA, err = c.CoreV1().Pods(ns).Create(testPodA)
84+
85+
By("creating a configmap with label A and ensuring the correct watchers observe the notification")
86+
testConfigMapA, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMapA)
9287
Expect(err).NotTo(HaveOccurred())
93-
expectEvent(watchA, watch.Added, testPodA)
94-
expectEvent(watchAB, watch.Added, testPodA)
95-
expectNoEvent(watchB, watch.Added, testPodA)
88+
expectEvent(watchA, watch.Added, testConfigMapA)
89+
expectEvent(watchAB, watch.Added, testConfigMapA)
90+
expectNoEvent(watchB, watch.Added, testConfigMapA)
9691

97-
testPodA, err = updatePod(f, testPodA.GetName(), func(p *v1.Pod) {
98-
p.ObjectMeta.Labels["mutation"] = "1"
92+
By("modifying configmap A and ensuring the correct watchers observe the notification")
93+
testConfigMapA, err = updateConfigMap(c, ns, testConfigMapA.GetName(), func(cm *v1.ConfigMap) {
94+
setConfigMapData(cm, "mutation", "1")
9995
})
10096
Expect(err).NotTo(HaveOccurred())
101-
expectEvent(watchA, watch.Modified, testPodA)
102-
expectEvent(watchAB, watch.Modified, testPodA)
103-
expectNoEvent(watchB, watch.Modified, testPodA)
97+
expectEvent(watchA, watch.Modified, testConfigMapA)
98+
expectEvent(watchAB, watch.Modified, testConfigMapA)
99+
expectNoEvent(watchB, watch.Modified, testConfigMapA)
104100

105-
testPodA, err = updatePod(f, testPodA.GetName(), func(p *v1.Pod) {
106-
p.ObjectMeta.Labels["mutation"] = "2"
101+
By("modifying configmap A again and ensuring the correct watchers observe the notification")
102+
testConfigMapA, err = updateConfigMap(c, ns, testConfigMapA.GetName(), func(cm *v1.ConfigMap) {
103+
setConfigMapData(cm, "mutation", "2")
107104
})
108105
Expect(err).NotTo(HaveOccurred())
109-
expectEvent(watchA, watch.Modified, testPodA)
110-
expectEvent(watchAB, watch.Modified, testPodA)
111-
expectNoEvent(watchB, watch.Modified, testPodA)
106+
expectEvent(watchA, watch.Modified, testConfigMapA)
107+
expectEvent(watchAB, watch.Modified, testConfigMapA)
108+
expectNoEvent(watchB, watch.Modified, testConfigMapA)
112109

113-
err = c.CoreV1().Pods(ns).Delete(testPodA.GetName(), nil)
110+
By("deleting configmap A and ensuring the correct watchers observe the notification")
111+
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMapA.GetName(), nil)
114112
Expect(err).NotTo(HaveOccurred())
115113
expectEvent(watchA, watch.Deleted, nil)
116114
expectEvent(watchAB, watch.Deleted, nil)
117115
expectNoEvent(watchB, watch.Deleted, nil)
118116

119-
testPodB, err = c.CoreV1().Pods(ns).Create(testPodB)
117+
By("creating a configmap with label B and ensuring the correct watchers observe the notification")
118+
testConfigMapB, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMapB)
120119
Expect(err).NotTo(HaveOccurred())
121-
expectEvent(watchB, watch.Added, testPodB)
122-
expectEvent(watchAB, watch.Added, testPodB)
123-
expectNoEvent(watchA, watch.Added, testPodB)
120+
expectEvent(watchB, watch.Added, testConfigMapB)
121+
expectEvent(watchAB, watch.Added, testConfigMapB)
122+
expectNoEvent(watchA, watch.Added, testConfigMapB)
124123

125-
err = c.CoreV1().Pods(ns).Delete(testPodB.GetName(), nil)
124+
By("deleting configmap B and ensuring the correct watchers observe the notification")
125+
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMapB.GetName(), nil)
126126
Expect(err).NotTo(HaveOccurred())
127127
expectEvent(watchB, watch.Deleted, nil)
128128
expectEvent(watchAB, watch.Deleted, nil)
129129
expectNoEvent(watchA, watch.Deleted, nil)
130130
})
131+
132+
/*
133+
Testname: watch-configmaps-from-resource-version
134+
Description: Ensure that a watch can be opened from a particular resource version
135+
in the past and only notifications happening after that resource version are observed.
136+
*/
137+
framework.ConformanceIt("should be able to start watching from a specific resource version", func() {
138+
c := f.ClientSet
139+
ns := f.Namespace.Name
140+
141+
testConfigMap := &v1.ConfigMap{
142+
ObjectMeta: metav1.ObjectMeta{
143+
Name: "e2e-watch-test-resource-version",
144+
Labels: map[string]string{
145+
watchConfigMapLabelKey: fromResourceVersionLabelValue,
146+
},
147+
},
148+
}
149+
150+
By("creating a new configmap")
151+
testConfigMap, err := c.CoreV1().ConfigMaps(ns).Create(testConfigMap)
152+
Expect(err).NotTo(HaveOccurred())
153+
154+
By("modifying the configmap once")
155+
testConfigMapFirstUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
156+
setConfigMapData(cm, "mutation", "1")
157+
})
158+
Expect(err).NotTo(HaveOccurred())
159+
160+
By("modifying the configmap a second time")
161+
testConfigMapSecondUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
162+
setConfigMapData(cm, "mutation", "2")
163+
})
164+
Expect(err).NotTo(HaveOccurred())
165+
166+
By("deleting the configmap")
167+
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMap.GetName(), nil)
168+
Expect(err).NotTo(HaveOccurred())
169+
170+
By("creating a watch on configmaps from the resource version returned by the first update")
171+
testWatch, err := watchConfigMaps(f, testConfigMapFirstUpdate.ObjectMeta.ResourceVersion, fromResourceVersionLabelValue)
172+
Expect(err).NotTo(HaveOccurred())
173+
174+
By("Expecting to observe notifications for all changes to the configmap after the first update")
175+
expectEvent(testWatch, watch.Modified, testConfigMapSecondUpdate)
176+
expectEvent(testWatch, watch.Deleted, nil)
177+
})
178+
179+
/*
180+
Testname: watch-configmaps-closed-and-restarted
181+
Description: Ensure that a watch can be reopened from the last resource version
182+
observed by the previous watch, and it will continue delivering notifications from
183+
that point in time.
184+
*/
185+
framework.ConformanceIt("should be able to restart watching from the last resource version observed by the previous watch", func() {
186+
c := f.ClientSet
187+
ns := f.Namespace.Name
188+
189+
testConfigMap := &v1.ConfigMap{
190+
ObjectMeta: metav1.ObjectMeta{
191+
Name: "e2e-watch-test-watch-closed",
192+
Labels: map[string]string{
193+
watchConfigMapLabelKey: watchRestartedLabelValue,
194+
},
195+
},
196+
}
197+
198+
By("creating a watch on configmaps")
199+
testWatchBroken, err := watchConfigMaps(f, "", watchRestartedLabelValue)
200+
Expect(err).NotTo(HaveOccurred())
201+
202+
By("creating a new configmap")
203+
testConfigMap, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMap)
204+
Expect(err).NotTo(HaveOccurred())
205+
206+
By("modifying the configmap once")
207+
_, err = updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
208+
setConfigMapData(cm, "mutation", "1")
209+
})
210+
Expect(err).NotTo(HaveOccurred())
211+
212+
By("closing the watch once it receives two notifications")
213+
expectEvent(testWatchBroken, watch.Added, testConfigMap)
214+
lastEvent, ok := waitForEvent(testWatchBroken, watch.Modified, nil, 1*time.Minute)
215+
if !ok {
216+
framework.Failf("Timed out waiting for second watch notification")
217+
}
218+
testWatchBroken.Stop()
219+
220+
By("modifying the configmap a second time, while the watch is closed")
221+
testConfigMapSecondUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
222+
setConfigMapData(cm, "mutation", "2")
223+
})
224+
Expect(err).NotTo(HaveOccurred())
225+
226+
By("creating a new watch on configmaps from the last resource version observed by the first watch")
227+
lastEventConfigMap, ok := lastEvent.Object.(*v1.ConfigMap)
228+
if !ok {
229+
framework.Failf("Expected last notfication to refer to a configmap but got: %v", lastEvent)
230+
}
231+
testWatchRestarted, err := watchConfigMaps(f, lastEventConfigMap.ObjectMeta.ResourceVersion, watchRestartedLabelValue)
232+
Expect(err).NotTo(HaveOccurred())
233+
234+
By("deleting the configmap")
235+
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMap.GetName(), nil)
236+
Expect(err).NotTo(HaveOccurred())
237+
238+
By("Expecting to observe notifications for all changes to the configmap since the first watch closed")
239+
expectEvent(testWatchRestarted, watch.Modified, testConfigMapSecondUpdate)
240+
expectEvent(testWatchRestarted, watch.Deleted, nil)
241+
})
242+
243+
/*
244+
Testname: watch-configmaps-label-changed
245+
Description: Ensure that a watched object stops meeting the requirements of
246+
a watch's selector, the watch will observe a delete, and will not observe
247+
notifications for that object until it meets the selector's requirements again.
248+
*/
249+
framework.ConformanceIt("should observe an object deletion if it stops meeting the requirements of the selector", func() {
250+
c := f.ClientSet
251+
ns := f.Namespace.Name
252+
253+
testConfigMap := &v1.ConfigMap{
254+
ObjectMeta: metav1.ObjectMeta{
255+
Name: "e2e-watch-test-label-changed",
256+
Labels: map[string]string{
257+
watchConfigMapLabelKey: toBeChangedLabelValue,
258+
},
259+
},
260+
}
261+
262+
By("creating a watch on configmaps with a certain label")
263+
testWatch, err := watchConfigMaps(f, "", toBeChangedLabelValue)
264+
Expect(err).NotTo(HaveOccurred())
265+
266+
By("creating a new configmap")
267+
testConfigMap, err = c.CoreV1().ConfigMaps(ns).Create(testConfigMap)
268+
Expect(err).NotTo(HaveOccurred())
269+
270+
By("modifying the configmap once")
271+
testConfigMapFirstUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
272+
setConfigMapData(cm, "mutation", "1")
273+
})
274+
Expect(err).NotTo(HaveOccurred())
275+
276+
By("changing the label value of the configmap")
277+
_, err = updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
278+
cm.ObjectMeta.Labels[watchConfigMapLabelKey] = "wrong-value"
279+
})
280+
Expect(err).NotTo(HaveOccurred())
281+
282+
By("Expecting to observe a delete notification for the watched object")
283+
expectEvent(testWatch, watch.Added, testConfigMap)
284+
expectEvent(testWatch, watch.Modified, testConfigMapFirstUpdate)
285+
expectEvent(testWatch, watch.Deleted, nil)
286+
287+
By("modifying the configmap a second time")
288+
testConfigMapSecondUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
289+
setConfigMapData(cm, "mutation", "2")
290+
})
291+
Expect(err).NotTo(HaveOccurred())
292+
293+
By("Expecting not to observe a notification because the object no longer meets the selector's requirements")
294+
expectNoEvent(testWatch, watch.Modified, testConfigMapSecondUpdate)
295+
296+
By("changing the label value of the configmap back")
297+
testConfigMapLabelRestored, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
298+
cm.ObjectMeta.Labels[watchConfigMapLabelKey] = toBeChangedLabelValue
299+
})
300+
Expect(err).NotTo(HaveOccurred())
301+
302+
By("modifying the configmap a third time")
303+
testConfigMapThirdUpdate, err := updateConfigMap(c, ns, testConfigMap.GetName(), func(cm *v1.ConfigMap) {
304+
setConfigMapData(cm, "mutation", "3")
305+
})
306+
Expect(err).NotTo(HaveOccurred())
307+
308+
By("deleting the configmap")
309+
err = c.CoreV1().ConfigMaps(ns).Delete(testConfigMap.GetName(), nil)
310+
Expect(err).NotTo(HaveOccurred())
311+
312+
By("Expecting to observe an add notification for the watched object when the label value was restored")
313+
expectEvent(testWatch, watch.Added, testConfigMapLabelRestored)
314+
expectEvent(testWatch, watch.Modified, testConfigMapThirdUpdate)
315+
expectEvent(testWatch, watch.Deleted, nil)
316+
})
131317
})
132318

133-
func watchPodsWithLabels(f *framework.Framework, labels ...string) (watch.Interface, error) {
319+
func watchConfigMaps(f *framework.Framework, resourceVersion string, labels ...string) (watch.Interface, error) {
134320
c := f.ClientSet
135321
ns := f.Namespace.Name
136322
opts := metav1.ListOptions{
323+
ResourceVersion: resourceVersion,
137324
LabelSelector: metav1.FormatLabelSelector(&metav1.LabelSelector{
138325
MatchExpressions: []metav1.LabelSelectorRequirement{
139326
{
140-
Key: watchPodLabelKey,
327+
Key: watchConfigMapLabelKey,
141328
Operator: metav1.LabelSelectorOpIn,
142329
Values: labels,
143330
},
144331
},
145332
}),
146333
}
147-
return c.CoreV1().Pods(ns).Watch(opts)
334+
return c.CoreV1().ConfigMaps(ns).Watch(opts)
148335
}
149336

150337
func int64ptr(i int) *int64 {
151338
i64 := int64(i)
152339
return &i64
153340
}
154341

155-
type updatePodFunc func(p *v1.Pod)
156-
157-
func updatePod(f *framework.Framework, name string, update updatePodFunc) (*v1.Pod, error) {
158-
c := f.ClientSet
159-
ns := f.Namespace.Name
160-
var p *v1.Pod
161-
pollErr := wait.PollImmediate(2*time.Second, 1*time.Minute, func() (bool, error) {
162-
var err error
163-
if p, err = c.CoreV1().Pods(ns).Get(name, metav1.GetOptions{}); err != nil {
164-
return false, err
165-
}
166-
update(p)
167-
if p, err = c.CoreV1().Pods(ns).Update(p); err == nil {
168-
return true, nil
169-
}
170-
// Only retry update on conflict
171-
if !errors.IsConflict(err) {
172-
return false, err
173-
}
174-
return false, nil
175-
})
176-
return p, pollErr
342+
func setConfigMapData(cm *v1.ConfigMap, key, value string) {
343+
if cm.Data == nil {
344+
cm.Data = make(map[string]string)
345+
}
346+
cm.Data[key] = value
177347
}
178348

179349
func expectEvent(w watch.Interface, eventType watch.EventType, object runtime.Object) {
180350
if event, ok := waitForEvent(w, eventType, object, 1*time.Minute); !ok {
181-
framework.Failf("Timed out waiting for expected event: %v", event)
351+
framework.Failf("Timed out waiting for expected watch notification: %v", event)
182352
}
183353
}
184354

185355
func expectNoEvent(w watch.Interface, eventType watch.EventType, object runtime.Object) {
186356
if event, ok := waitForEvent(w, eventType, object, 10*time.Second); ok {
187-
framework.Failf("Unexpected event occurred: %v", event)
357+
framework.Failf("Unexpected watch notification observed: %v", event)
188358
}
189359
}
190360

0 commit comments

Comments
 (0)
Please sign in to comment.