Skip to content

Commit 3db3a5f

Browse files
e2e: removed validating job (#2174)
1 parent f03aa5d commit 3db3a5f

22 files changed

Lines changed: 1179 additions & 1459 deletions

test/e2e/childobjects/vmalertmanagerconfig_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"strings"
7+
"time"
78

89
. "github.com/onsi/ginkgo/v2"
910
. "github.com/onsi/gomega"
@@ -57,13 +58,12 @@ var _ = Describe("test vmalertmanagerconfig Controller", Label("vm", "child", "a
5758
}
5859

5960
for _, am := range args.ams {
60-
Eventually(func() error {
61-
return suite.ExpectObjectStatus(ctx,
62-
k8sClient,
63-
&vmv1beta1.VMAlertmanager{},
64-
types.NamespacedName{Name: am.Name, Namespace: am.Namespace},
65-
vmv1beta1.UpdateStatusOperational)
66-
}, eventualReadyTimeout).ShouldNot(HaveOccurred())
61+
Expect(suite.WatchUntilStatusReached(ctx, k8sClient,
62+
&vmv1beta1.VMAlertmanagerList{},
63+
types.NamespacedName{Name: am.Name, Namespace: am.Namespace},
64+
eventualReadyTimeout*time.Second,
65+
vmv1beta1.UpdateStatusOperational,
66+
vmv1beta1.UpdateStatusFailed)).ToNot(HaveOccurred())
6767
}
6868
if step.modify != nil {
6969
step.modify()

test/e2e/childobjects/vmrule_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"strings"
7+
"time"
78

89
. "github.com/onsi/ginkgo/v2"
910
. "github.com/onsi/gomega"
@@ -57,13 +58,12 @@ var _ = Describe("test vmrule Controller", Label("vm", "child", "alert"), func()
5758
}
5859

5960
for _, alert := range args.alerts {
60-
Eventually(func() error {
61-
return suite.ExpectObjectStatus(ctx,
62-
k8sClient,
63-
&vmv1beta1.VMAlert{},
64-
types.NamespacedName{Name: alert.Name, Namespace: alert.Namespace},
65-
vmv1beta1.UpdateStatusOperational)
66-
}, eventualReadyTimeout).ShouldNot(HaveOccurred())
61+
Expect(suite.WatchUntilStatusReached(ctx, k8sClient,
62+
&vmv1beta1.VMAlertList{},
63+
types.NamespacedName{Name: alert.Name, Namespace: alert.Namespace},
64+
eventualReadyTimeout*time.Second,
65+
vmv1beta1.UpdateStatusOperational,
66+
vmv1beta1.UpdateStatusFailed)).ToNot(HaveOccurred())
6767
}
6868
if step.modify != nil {
6969
step.modify()

test/e2e/childobjects/vmuser_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package childobjects
33
import (
44
"context"
55
"fmt"
6+
"time"
67

78
. "github.com/onsi/ginkgo/v2"
89
. "github.com/onsi/gomega"
@@ -58,13 +59,12 @@ var _ = Describe("test vmuser Controller", Label("vm", "child", "auth"), func()
5859
}
5960

6061
for _, am := range args.vmauths {
61-
Eventually(func() error {
62-
return suite.ExpectObjectStatus(ctx,
63-
k8sClient,
64-
&vmv1beta1.VMAuth{},
65-
types.NamespacedName{Name: am.Name, Namespace: am.Namespace},
66-
vmv1beta1.UpdateStatusOperational)
67-
}, eventualReadyTimeout).ShouldNot(HaveOccurred())
62+
Expect(suite.WatchUntilStatusReached(ctx, k8sClient,
63+
&vmv1beta1.VMAuthList{},
64+
types.NamespacedName{Name: am.Name, Namespace: am.Namespace},
65+
eventualReadyTimeout*time.Second,
66+
vmv1beta1.UpdateStatusOperational,
67+
vmv1beta1.UpdateStatusFailed)).ToNot(HaveOccurred())
6868
}
6969
if step.modify != nil {
7070
step.modify()

test/e2e/e2e_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
. "github.com/onsi/ginkgo/v2"
2525
. "github.com/onsi/gomega"
26+
"k8s.io/client-go/rest"
2627
"sigs.k8s.io/controller-runtime/pkg/client"
2728

2829
"github.com/VictoriaMetrics/operator/test/e2e/suite"
@@ -36,23 +37,27 @@ var (
3637
eventualDeploymentPodTimeout = 25 * time.Second
3738
eventualExpandingTimeout = 25 * time.Second
3839
eventualDistributedExpandingTimeout = 5 * time.Minute
40+
eventualPollingInterval = 2 * time.Second
3941
)
4042

4143
// Run e2e tests using the Ginkgo runner.
4244
func TestE2E(t *testing.T) {
4345
RegisterFailHandler(Fail)
46+
SetDefaultEventuallyPollingInterval(eventualPollingInterval)
4447
fmt.Fprintf(GinkgoWriter, "Starting vm-operator suite\n")
4548
suiteConfig, reporterConfig := GinkgoConfiguration()
4649
RunSpecs(t, "End2End Suite", suiteConfig, reporterConfig)
4750
}
4851

4952
var (
5053
k8sClient client.WithWatch
54+
k8sCfg rest.Config
5155

5256
_ = SynchronizedBeforeSuite(func() []byte {
5357
return suite.InitOperatorProcess()
5458
}, func(data []byte) {
5559
k8sClient = suite.GetClient(data)
60+
k8sCfg = suite.GetRestConfig(data)
5661
})
5762

5863
_ = SynchronizedAfterSuite(func() {}, func() {

test/e2e/prometheus_converter_test.go

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
. "github.com/onsi/gomega"
99
promv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
1010
promv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
11-
k8serrors "k8s.io/apimachinery/pkg/api/errors"
1211
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1312
"k8s.io/apimachinery/pkg/types"
1413
"k8s.io/apimachinery/pkg/util/intstr"
@@ -310,16 +309,10 @@ var _ = Describe("test prometheusConverter Controller", func() {
310309
Context(fmt.Sprintf("crud %s", testCase.name), func() {
311310
AfterEach(func() {
312311
k8sClient.Delete(ctx, testCase.source) // nolint:errcheck
313-
Eventually(func() error {
314-
_, err := getObject(ctx, testCase.source)
315-
return err
316-
}, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))
312+
waitObjectDeleted(ctx, testCase.source)
317313

318314
k8sClient.Delete(ctx, testCase.targetTpl) // nolint:errcheck
319-
Eventually(func() error {
320-
_, err := getObject(ctx, testCase.targetTpl)
321-
return err
322-
}, 60, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))
315+
waitObjectDeleted(ctx, testCase.targetTpl)
323316
})
324317

325318
It("Should convert the object", func() {
@@ -388,10 +381,7 @@ var _ = Describe("test prometheusConverter Controller", func() {
388381
return nil
389382
}()).ToNot(HaveOccurred())
390383
Expect(k8sClient.Delete(ctx, source)).ToNot(HaveOccurred())
391-
Eventually(func() error {
392-
_, err := getObject(ctx, testCase.targetTpl)
393-
return err
394-
}, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))
384+
waitObjectDeleted(ctx, testCase.targetTpl)
395385
})
396386
})
397387
}

test/e2e/suite/suite.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ var (
4343
stopped = make(chan struct{})
4444
)
4545

46+
func GetRestConfig(data []byte) rest.Config {
47+
var cfg rest.Config
48+
dec := gob.NewDecoder(bytes.NewReader(data))
49+
Expect(dec.Decode(&cfg)).To(Succeed())
50+
return cfg
51+
}
52+
4653
func GetClient(data []byte) client.WithWatch {
4754
var cfg rest.Config
4855
dec := gob.NewDecoder(bytes.NewReader(data))

test/e2e/suite/utils.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99

1010
. "github.com/onsi/ginkgo/v2" //nolint
1111
. "github.com/onsi/gomega" //nolint
12+
"k8s.io/apimachinery/pkg/fields"
1213
k8stypes "k8s.io/apimachinery/pkg/types"
14+
watchapi "k8s.io/apimachinery/pkg/watch"
1315
"sigs.k8s.io/controller-runtime/pkg/client"
1416

1517
vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
@@ -48,12 +50,122 @@ func ExpectObjectStatus(ctx context.Context,
4850
for _, cond := range obs.Status.Conditions {
4951
conds = append(conds, fmt.Sprintf("type=%s,message=%q,generation=%d,status=%q", cond.Type, cond.Message, cond.ObservedGeneration, cond.Status))
5052
}
53+
if obs.Status.UpdateStatus == vmv1beta1.UpdateStatusFailed && status != vmv1beta1.UpdateStatusFailed {
54+
return StopTrying(fmt.Sprintf("object %q entered %q while waiting for %q: reason=%q,conditions=%s",
55+
name.Name, obs.Status.UpdateStatus, status, obs.Status.Reason, strings.Join(conds, ",")))
56+
}
5157
return fmt.Errorf("not expected object status=%q, reason=%q,conditions=%s", obs.Status.UpdateStatus, obs.Status.Reason, strings.Join(conds, ","))
5258
}
5359

5460
return nil
5561
}
5662

63+
// WatchUntilStatusSeen reads events from w until it observes an object with the given name,
64+
// observedGeneration >= minGen, and target status, or the context deadline is reached.
65+
// Start the watch before triggering the action, then pass the post-action generation as minGen
66+
// to avoid matching stale pre-action ADDED events that share the same name and status.
67+
// If a failStatuses entry is seen (with obsGen >= minGen and status != targetStatus),
68+
// WatchUntilStatusSeen returns immediately with the failure reason rather than waiting for timeout.
69+
// All matched events are logged to GinkgoWriter for post-failure diagnostics.
70+
func WatchUntilStatusSeen(ctx context.Context, w watchapi.Interface, name string, minGen int64, targetStatus vmv1beta1.UpdateStatus, failStatuses ...vmv1beta1.UpdateStatus) error {
71+
for {
72+
select {
73+
case event, ok := <-w.ResultChan():
74+
if !ok {
75+
return fmt.Errorf("watch closed before observing status %q for %q", targetStatus, name)
76+
}
77+
if event.Type == watchapi.Error {
78+
return fmt.Errorf("watch error: %v", event.Object)
79+
}
80+
obj, ok := event.Object.(client.Object)
81+
if !ok || obj.GetName() != name {
82+
continue
83+
}
84+
jsD, err := json.Marshal(obj)
85+
if err != nil {
86+
continue
87+
}
88+
type statusHolder struct {
89+
Status struct {
90+
vmv1beta1.StatusMetadata `json:",inline"`
91+
} `json:"status"`
92+
}
93+
var sh statusHolder
94+
if err := json.Unmarshal(jsD, &sh); err != nil {
95+
continue
96+
}
97+
obsGen := sh.Status.ObservedGeneration
98+
status := sh.Status.UpdateStatus
99+
fmt.Fprintf(GinkgoWriter, "[watch] %s name=%s gen=%d obsGen=%d status=%q",
100+
event.Type, name, obj.GetGeneration(), obsGen, status)
101+
if status == targetStatus && obsGen >= minGen {
102+
fmt.Fprintf(GinkgoWriter, " ✓\n")
103+
return nil
104+
}
105+
if obsGen >= minGen {
106+
for _, fs := range failStatuses {
107+
if status == fs {
108+
var conds []string
109+
for _, cond := range sh.Status.Conditions {
110+
conds = append(conds, fmt.Sprintf("type=%s,message=%q", cond.Type, cond.Message))
111+
}
112+
fmt.Fprintf(GinkgoWriter, " (fail-fast)\n")
113+
return fmt.Errorf("object %q entered %q while waiting for %q: reason=%q conditions=%s",
114+
name, status, targetStatus, sh.Status.Reason, strings.Join(conds, ","))
115+
}
116+
}
117+
fmt.Fprintf(GinkgoWriter, " (skipped: status %q != %q)\n", status, targetStatus)
118+
} else {
119+
fmt.Fprintf(GinkgoWriter, " (skipped: obsGen %d < minGen %d)\n", obsGen, minGen)
120+
}
121+
case <-ctx.Done():
122+
return fmt.Errorf("timed out waiting for status %q for object %q: %w", targetStatus, name, ctx.Err())
123+
}
124+
}
125+
}
126+
127+
// WatchUntilStatusReached starts a watch on the named object and waits until it reaches targetStatus.
128+
// Uses minGen=0 (matches any generation), suitable when there is no preceding mutation to guard against.
129+
// Pass failStatuses to return immediately if an unexpected failure state is observed before targetStatus.
130+
func WatchUntilStatusReached(ctx context.Context, rclient client.WithWatch, list client.ObjectList, nsn k8stypes.NamespacedName, timeout time.Duration, targetStatus vmv1beta1.UpdateStatus, failStatuses ...vmv1beta1.UpdateStatus) error {
131+
listOpts := &client.ListOptions{
132+
Namespace: nsn.Namespace,
133+
FieldSelector: fields.OneTermEqualSelector("metadata.name", nsn.Name),
134+
}
135+
watcher, err := rclient.Watch(ctx, list, listOpts)
136+
if err != nil {
137+
return err
138+
}
139+
defer watcher.Stop()
140+
watchCtx, cancel := context.WithTimeout(ctx, timeout)
141+
defer cancel()
142+
return WatchUntilStatusSeen(watchCtx, watcher, nsn.Name, 0, targetStatus, failStatuses...)
143+
}
144+
145+
// WatchUntilDeleted reads events from w until it observes a DELETED event for the named
146+
// object, or the context deadline is reached.
147+
func WatchUntilDeleted(ctx context.Context, w watchapi.Interface, name string) error {
148+
for {
149+
select {
150+
case event, ok := <-w.ResultChan():
151+
if !ok {
152+
return fmt.Errorf("watch closed before observing deletion of %q", name)
153+
}
154+
if event.Type == watchapi.Error {
155+
return fmt.Errorf("watch error: %v", event.Object)
156+
}
157+
if event.Type == watchapi.Deleted {
158+
obj, ok := event.Object.(client.Object)
159+
if ok && obj.GetName() == name {
160+
return nil
161+
}
162+
}
163+
case <-ctx.Done():
164+
return fmt.Errorf("timed out waiting for deletion of object %q: %w", name, ctx.Err())
165+
}
166+
}
167+
}
168+
57169
func CollectK8SResources() {
58170
if !CurrentSpecReport().Failed() {
59171
return

0 commit comments

Comments
 (0)