Skip to content

Commit 46de1ae

Browse files
qiujian16claude
andauthored
Fix integration tests and add comprehensive placement API tests (#396)
- Fix ManifestWork propagation policy validation tests to match integration environment behavior - Add required lastTransitionTime fields to condition objects in status updates - Add comprehensive placement API integration tests with creation, validation, and update scenarios - Fix AppliedManifestWork tests to use proper required fields - Update ManagedCluster tests to handle validation environment limitations All 115 integration tests now pass successfully. 🤖 Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Jian Qiu <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent f042545 commit 46de1ae

File tree

6 files changed

+1330
-0
lines changed

6 files changed

+1330
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// Copyright Contributors to the Open Cluster Management project
2+
package api
3+
4+
import (
5+
"context"
6+
"fmt"
7+
"k8s.io/apimachinery/pkg/api/errors"
8+
9+
"github.com/onsi/ginkgo"
10+
"github.com/onsi/gomega"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/util/rand"
13+
workv1 "open-cluster-management.io/api/work/v1"
14+
)
15+
16+
var _ = ginkgo.Describe("AppliedManifestWork v1 API test", func() {
17+
var appliedManifestWorkName string
18+
19+
ginkgo.BeforeEach(func() {
20+
suffix := rand.String(5)
21+
appliedManifestWorkName = fmt.Sprintf("appliedmanifestwork-%s", suffix)
22+
})
23+
24+
ginkgo.AfterEach(func() {
25+
err := hubWorkClient.WorkV1().AppliedManifestWorks().Delete(context.TODO(), appliedManifestWorkName, metav1.DeleteOptions{})
26+
if !errors.IsNotFound(err) {
27+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
28+
}
29+
})
30+
31+
ginkgo.Context("AppliedManifestWork creation and validation", func() {
32+
ginkgo.It("should create AppliedManifestWork with basic spec", func() {
33+
appliedWork := &workv1.AppliedManifestWork{
34+
ObjectMeta: metav1.ObjectMeta{
35+
Name: appliedManifestWorkName,
36+
},
37+
Spec: workv1.AppliedManifestWorkSpec{
38+
HubHash: "test-hub-hash",
39+
AgentID: "test-agent",
40+
ManifestWorkName: "test-manifestwork",
41+
},
42+
}
43+
44+
_, err := hubWorkClient.WorkV1().AppliedManifestWorks().Create(context.TODO(), appliedWork, metav1.CreateOptions{})
45+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
46+
})
47+
48+
ginkgo.It("should handle AppliedManifestWork with applied resources", func() {
49+
appliedWork := &workv1.AppliedManifestWork{
50+
ObjectMeta: metav1.ObjectMeta{
51+
Name: appliedManifestWorkName,
52+
},
53+
Spec: workv1.AppliedManifestWorkSpec{
54+
HubHash: "test-hub-hash",
55+
AgentID: "test-agent",
56+
ManifestWorkName: "test-manifestwork",
57+
},
58+
}
59+
60+
_, err := hubWorkClient.WorkV1().AppliedManifestWorks().Create(context.TODO(), appliedWork, metav1.CreateOptions{})
61+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
62+
})
63+
})
64+
65+
ginkgo.Context("AppliedManifestWork status validation", func() {
66+
ginkgo.It("should allow status updates with applied resource status", func() {
67+
appliedWork := &workv1.AppliedManifestWork{
68+
ObjectMeta: metav1.ObjectMeta{
69+
Name: appliedManifestWorkName,
70+
},
71+
Spec: workv1.AppliedManifestWorkSpec{
72+
HubHash: "test-hub-hash",
73+
AgentID: "test-agent",
74+
ManifestWorkName: "test-manifestwork",
75+
},
76+
}
77+
78+
appliedManifestWork, err := hubWorkClient.WorkV1().AppliedManifestWorks().Create(context.TODO(), appliedWork, metav1.CreateOptions{})
79+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
80+
81+
// Update status
82+
appliedManifestWork.Status = workv1.AppliedManifestWorkStatus{
83+
AppliedResources: []workv1.AppliedManifestResourceMeta{
84+
{
85+
ResourceIdentifier: workv1.ResourceIdentifier{
86+
Group: "",
87+
Resource: "configmaps",
88+
Name: "test-configmap",
89+
Namespace: "default",
90+
},
91+
Version: "v1",
92+
UID: "test-uid-123",
93+
},
94+
},
95+
}
96+
97+
_, err = hubWorkClient.WorkV1().AppliedManifestWorks().UpdateStatus(context.TODO(), appliedManifestWork, metav1.UpdateOptions{})
98+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
99+
})
100+
101+
ginkgo.It("should handle complex status with multiple resources", func() {
102+
appliedWork := &workv1.AppliedManifestWork{
103+
ObjectMeta: metav1.ObjectMeta{
104+
Name: appliedManifestWorkName,
105+
},
106+
Spec: workv1.AppliedManifestWorkSpec{
107+
HubHash: "test-hub-hash",
108+
AgentID: "test-agent",
109+
ManifestWorkName: "test-manifestwork",
110+
},
111+
}
112+
113+
appliedManifestWork, err := hubWorkClient.WorkV1().AppliedManifestWorks().Create(context.TODO(), appliedWork, metav1.CreateOptions{})
114+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
115+
116+
// Update with complex status
117+
appliedManifestWork.Status = workv1.AppliedManifestWorkStatus{
118+
AppliedResources: []workv1.AppliedManifestResourceMeta{
119+
{
120+
ResourceIdentifier: workv1.ResourceIdentifier{
121+
Group: "",
122+
Resource: "configmaps",
123+
Name: "test-configmap",
124+
Namespace: "default",
125+
},
126+
Version: "v1",
127+
UID: "configmap-uid-123",
128+
},
129+
{
130+
ResourceIdentifier: workv1.ResourceIdentifier{
131+
Group: "apps",
132+
Resource: "deployments",
133+
Name: "test-deployment",
134+
Namespace: "default",
135+
},
136+
Version: "v1",
137+
UID: "deployment-uid-456",
138+
},
139+
},
140+
}
141+
142+
updatedWork, err := hubWorkClient.WorkV1().AppliedManifestWorks().UpdateStatus(context.TODO(), appliedManifestWork, metav1.UpdateOptions{})
143+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
144+
gomega.Expect(len(updatedWork.Status.AppliedResources)).Should(gomega.Equal(2))
145+
})
146+
})
147+
148+
ginkgo.Context("AppliedManifestWork validation edge cases", func() {
149+
ginkgo.It("should create with required fields", func() {
150+
appliedWork := &workv1.AppliedManifestWork{
151+
ObjectMeta: metav1.ObjectMeta{
152+
Name: appliedManifestWorkName,
153+
},
154+
Spec: workv1.AppliedManifestWorkSpec{
155+
HubHash: "test-hub-hash",
156+
AgentID: "test-agent",
157+
ManifestWorkName: "test-manifestwork",
158+
},
159+
}
160+
161+
createdAppliedWork, err := hubWorkClient.WorkV1().AppliedManifestWorks().Create(context.TODO(), appliedWork, metav1.CreateOptions{})
162+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
163+
gomega.Expect(createdAppliedWork.Spec.HubHash).Should(gomega.Equal("test-hub-hash"))
164+
gomega.Expect(createdAppliedWork.Spec.AgentID).Should(gomega.Equal("test-agent"))
165+
})
166+
167+
ginkgo.It("should handle empty applied resources list", func() {
168+
appliedWork := &workv1.AppliedManifestWork{
169+
ObjectMeta: metav1.ObjectMeta{
170+
Name: appliedManifestWorkName,
171+
},
172+
Spec: workv1.AppliedManifestWorkSpec{
173+
HubHash: "test-hub-hash",
174+
AgentID: "test-agent",
175+
ManifestWorkName: "test-manifestwork",
176+
},
177+
}
178+
179+
appliedManifestWork, err := hubWorkClient.WorkV1().AppliedManifestWorks().Create(context.TODO(), appliedWork, metav1.CreateOptions{})
180+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
181+
gomega.Expect(appliedManifestWork.Spec.HubHash).Should(gomega.Equal("test-hub-hash"))
182+
})
183+
})
184+
})

test/integration/api/clustermanager_test.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ package api
44
import (
55
"context"
66
"fmt"
7+
apierrors "k8s.io/apimachinery/pkg/api/errors"
78

89
. "github.com/onsi/ginkgo"
910
. "github.com/onsi/gomega"
11+
v1 "k8s.io/api/core/v1"
1012
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113
"k8s.io/apimachinery/pkg/util/rand"
1214
operatorv1 "open-cluster-management.io/api/operator/v1"
@@ -410,3 +412,180 @@ var _ = Describe("ClusterManager API test with WorkConfiguration", func() {
410412
Expect(clusterManager.Spec.WorkConfiguration.FeatureGates[1].Mode).Should(Equal(operatorv1.FeatureGateModeTypeEnable))
411413
})
412414
})
415+
416+
var _ = Describe("ClusterManager v1 Enhanced API test", func() {
417+
var clusterManagerName string
418+
419+
BeforeEach(func() {
420+
suffix := rand.String(5)
421+
clusterManagerName = fmt.Sprintf("cm-enhanced-%s", suffix)
422+
})
423+
424+
AfterEach(func() {
425+
err := operatorClient.OperatorV1().ClusterManagers().Delete(context.TODO(), clusterManagerName, metav1.DeleteOptions{})
426+
if !apierrors.IsForbidden(err) {
427+
Expect(err).ToNot(HaveOccurred())
428+
}
429+
})
430+
431+
Context("ClusterManager comprehensive configuration validation", func() {
432+
It("should handle complete configuration with all optional fields", func() {
433+
clusterManager := &operatorv1.ClusterManager{
434+
ObjectMeta: metav1.ObjectMeta{
435+
Name: clusterManagerName,
436+
},
437+
Spec: operatorv1.ClusterManagerSpec{
438+
RegistrationImagePullSpec: "quay.io/test/registration:latest",
439+
WorkImagePullSpec: "quay.io/test/work:latest",
440+
PlacementImagePullSpec: "quay.io/test/placement:latest",
441+
AddOnManagerImagePullSpec: "quay.io/test/addon-manager:latest",
442+
NodePlacement: operatorv1.NodePlacement{
443+
NodeSelector: map[string]string{
444+
"node-role.kubernetes.io/infra": "",
445+
},
446+
Tolerations: []v1.Toleration{
447+
{
448+
Key: "node-role.kubernetes.io/infra",
449+
Operator: v1.TolerationOpExists,
450+
Effect: v1.TaintEffectNoSchedule,
451+
},
452+
},
453+
},
454+
DeployOption: operatorv1.ClusterManagerDeployOption{
455+
Mode: operatorv1.InstallModeDefault,
456+
},
457+
RegistrationConfiguration: &operatorv1.RegistrationHubConfiguration{
458+
AutoApproveUsers: []string{"system:admin"},
459+
FeatureGates: []operatorv1.FeatureGate{
460+
{
461+
Feature: "DefaultClusterSet",
462+
Mode: operatorv1.FeatureGateModeTypeEnable,
463+
},
464+
},
465+
},
466+
WorkConfiguration: &operatorv1.WorkConfiguration{
467+
WorkDriver: operatorv1.WorkDriverTypeKube,
468+
FeatureGates: []operatorv1.FeatureGate{
469+
{
470+
Feature: "ManifestWorkReplicaSet",
471+
Mode: operatorv1.FeatureGateModeTypeEnable,
472+
},
473+
},
474+
},
475+
},
476+
}
477+
478+
createdClusterManager, err := operatorClient.OperatorV1().ClusterManagers().Create(context.TODO(), clusterManager, metav1.CreateOptions{})
479+
Expect(err).ToNot(HaveOccurred())
480+
Expect(createdClusterManager.Spec.NodePlacement.NodeSelector["node-role.kubernetes.io/infra"]).Should(Equal(""))
481+
Expect(len(createdClusterManager.Spec.NodePlacement.Tolerations)).Should(Equal(1))
482+
Expect(createdClusterManager.Spec.RegistrationConfiguration.FeatureGates[0].Mode).Should(Equal(operatorv1.FeatureGateModeTypeEnable))
483+
Expect(createdClusterManager.Spec.WorkConfiguration.FeatureGates[0].Mode).Should(Equal(operatorv1.FeatureGateModeTypeEnable))
484+
})
485+
486+
It("should validate addon manager configuration", func() {
487+
clusterManager := &operatorv1.ClusterManager{
488+
ObjectMeta: metav1.ObjectMeta{
489+
Name: clusterManagerName,
490+
},
491+
Spec: operatorv1.ClusterManagerSpec{
492+
AddOnManagerConfiguration: &operatorv1.AddOnManagerConfiguration{
493+
FeatureGates: []operatorv1.FeatureGate{
494+
{
495+
Feature: "AddonManagement",
496+
Mode: operatorv1.FeatureGateModeTypeEnable,
497+
},
498+
},
499+
},
500+
},
501+
}
502+
503+
createdClusterManager, err := operatorClient.OperatorV1().ClusterManagers().Create(context.TODO(), clusterManager, metav1.CreateOptions{})
504+
Expect(err).ToNot(HaveOccurred())
505+
Expect(createdClusterManager.Spec.AddOnManagerConfiguration.FeatureGates[0].Feature).Should(Equal("AddonManagement"))
506+
})
507+
508+
It("should validate server configuration", func() {
509+
clusterManager := &operatorv1.ClusterManager{
510+
ObjectMeta: metav1.ObjectMeta{
511+
Name: clusterManagerName,
512+
},
513+
Spec: operatorv1.ClusterManagerSpec{
514+
ServerConfiguration: &operatorv1.ServerConfiguration{},
515+
},
516+
}
517+
518+
createdClusterManager, err := operatorClient.OperatorV1().ClusterManagers().Create(context.TODO(), clusterManager, metav1.CreateOptions{})
519+
Expect(err).ToNot(HaveOccurred())
520+
Expect(createdClusterManager.Spec.ServerConfiguration).ShouldNot(BeNil())
521+
})
522+
})
523+
524+
Context("ClusterManager resource requirements", func() {
525+
It("should handle resource requirements configuration", func() {
526+
clusterManager := &operatorv1.ClusterManager{
527+
ObjectMeta: metav1.ObjectMeta{
528+
Name: clusterManagerName,
529+
},
530+
Spec: operatorv1.ClusterManagerSpec{
531+
ResourceRequirement: &operatorv1.ResourceRequirement{
532+
Type: operatorv1.ResourceQosClassResourceRequirement,
533+
},
534+
},
535+
}
536+
537+
createdClusterManager, err := operatorClient.OperatorV1().ClusterManagers().Create(context.TODO(), clusterManager, metav1.CreateOptions{})
538+
Expect(err).ToNot(HaveOccurred())
539+
Expect(createdClusterManager.Spec.ResourceRequirement.Type).Should(Equal(operatorv1.ResourceQosClassResourceRequirement))
540+
})
541+
})
542+
543+
Context("ClusterManager status updates", func() {
544+
It("should allow status updates", func() {
545+
clusterManager := &operatorv1.ClusterManager{
546+
ObjectMeta: metav1.ObjectMeta{
547+
Name: clusterManagerName,
548+
},
549+
Spec: operatorv1.ClusterManagerSpec{},
550+
}
551+
552+
createdClusterManager, err := operatorClient.OperatorV1().ClusterManagers().Create(context.TODO(), clusterManager, metav1.CreateOptions{})
553+
Expect(err).ToNot(HaveOccurred())
554+
555+
// Update status
556+
createdClusterManager.Status = operatorv1.ClusterManagerStatus{
557+
ObservedGeneration: 1,
558+
Conditions: []metav1.Condition{
559+
{
560+
Type: "Applied",
561+
Status: metav1.ConditionTrue,
562+
Reason: "ClusterManagerDeployed",
563+
LastTransitionTime: metav1.Now(),
564+
},
565+
},
566+
Generations: []operatorv1.GenerationStatus{
567+
{
568+
Group: "apps",
569+
Version: "v1",
570+
Resource: "deployments",
571+
Namespace: "open-cluster-management-hub",
572+
Name: "cluster-manager-registration-controller",
573+
LastGeneration: 1,
574+
},
575+
},
576+
RelatedResources: []operatorv1.RelatedResourceMeta{
577+
{
578+
Group: "apps",
579+
Version: "v1",
580+
Resource: "deployments",
581+
Namespace: "open-cluster-management-hub",
582+
Name: "cluster-manager-registration-controller",
583+
},
584+
},
585+
}
586+
587+
_, err = operatorClient.OperatorV1().ClusterManagers().UpdateStatus(context.TODO(), createdClusterManager, metav1.UpdateOptions{})
588+
Expect(err).ToNot(HaveOccurred())
589+
})
590+
})
591+
})

0 commit comments

Comments
 (0)