mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-05-24 10:02:57 +00:00
216
test/e2e/placement_test.go
Normal file
216
test/e2e/placement_test.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
|
||||
clusterapiv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
clusterapiv1alpha1 "github.com/open-cluster-management/api/cluster/v1alpha1"
|
||||
"github.com/open-cluster-management/placement/test/integration/util"
|
||||
)
|
||||
|
||||
const (
|
||||
clusterSetLabel = "cluster.open-cluster-management.io/clusterset"
|
||||
placementLabel = "cluster.open-cluster-management.io/placement"
|
||||
)
|
||||
|
||||
var _ = ginkgo.Describe("Placement", func() {
|
||||
var namespace string
|
||||
var placementName string
|
||||
var clusterSet1Name string
|
||||
var suffix string
|
||||
var err error
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
suffix = rand.String(5)
|
||||
namespace = fmt.Sprintf("ns-%s", suffix)
|
||||
placementName = fmt.Sprintf("placement-%s", suffix)
|
||||
clusterSet1Name = fmt.Sprintf("clusterset-%s", suffix)
|
||||
|
||||
// create testing namespace
|
||||
ns := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
},
|
||||
}
|
||||
_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
})
|
||||
|
||||
ginkgo.AfterEach(func() {
|
||||
err := kubeClient.CoreV1().Namespaces().Delete(context.Background(), namespace, metav1.DeleteOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
})
|
||||
|
||||
assertPlacementDecisionCreated := func(placement *clusterapiv1alpha1.Placement) {
|
||||
ginkgo.By("Check if placementdecision is created")
|
||||
gomega.Eventually(func() bool {
|
||||
pdl, err := clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).List(context.Background(), metav1.ListOptions{
|
||||
LabelSelector: placementLabel + "=" + placement.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(pdl.Items) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, pd := range pdl.Items {
|
||||
if controlled := metav1.IsControlledBy(&pd.ObjectMeta, placement); !controlled {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
}
|
||||
|
||||
assertNumberOfDecisions := func(placementName string, desiredNOD int) {
|
||||
ginkgo.By("Check the number of decisions in placementdecisions")
|
||||
gomega.Eventually(func() bool {
|
||||
pdl, err := clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).List(context.Background(), metav1.ListOptions{
|
||||
LabelSelector: placementLabel + "=" + placementName,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(pdl.Items) == 0 {
|
||||
return false
|
||||
}
|
||||
actualNOD := 0
|
||||
for _, pd := range pdl.Items {
|
||||
actualNOD += len(pd.Status.Decisions)
|
||||
}
|
||||
return actualNOD == desiredNOD
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
}
|
||||
|
||||
assertPlacementStatus := func(placementName string, numOfSelectedClusters int, satisfied bool) {
|
||||
ginkgo.By("Check the status of placement")
|
||||
gomega.Eventually(func() bool {
|
||||
placement, err := clusterClient.ClusterV1alpha1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if satisfied && !util.HasCondition(
|
||||
placement.Status.Conditions,
|
||||
clusterapiv1alpha1.PlacementConditionSatisfied,
|
||||
"AllDecisionsScheduled",
|
||||
metav1.ConditionTrue,
|
||||
) {
|
||||
return false
|
||||
}
|
||||
if !satisfied && !util.HasCondition(
|
||||
placement.Status.Conditions,
|
||||
clusterapiv1alpha1.PlacementConditionSatisfied,
|
||||
"NotAllDecisionsScheduled",
|
||||
metav1.ConditionFalse,
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return placement.Status.NumberOfSelectedClusters == int32(numOfSelectedClusters)
|
||||
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
|
||||
}
|
||||
|
||||
assertBindingClusterSet := func(clusterSetName string) {
|
||||
ginkgo.By("Create clusterset/clustersetbinding")
|
||||
clusterset := &clusterapiv1alpha1.ManagedClusterSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterSetName,
|
||||
},
|
||||
}
|
||||
_, err = clusterClient.ClusterV1alpha1().ManagedClusterSets().Create(context.Background(), clusterset, metav1.CreateOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
csb := &clusterapiv1alpha1.ManagedClusterSetBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: clusterSetName,
|
||||
},
|
||||
Spec: clusterapiv1alpha1.ManagedClusterSetBindingSpec{
|
||||
ClusterSet: clusterSetName,
|
||||
},
|
||||
}
|
||||
_, err = clusterClient.ClusterV1alpha1().ManagedClusterSetBindings(namespace).Create(context.Background(), csb, metav1.CreateOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
}
|
||||
|
||||
assertCreatingClusters := func(clusterSetName string, num int) {
|
||||
ginkgo.By(fmt.Sprintf("Create %d clusters", num))
|
||||
for i := 0; i < num; i++ {
|
||||
cluster := &clusterapiv1.ManagedCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "cluster-",
|
||||
Labels: map[string]string{
|
||||
clusterSetLabel: clusterSetName,
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = clusterClient.ClusterV1().ManagedClusters().Create(context.Background(), cluster, metav1.CreateOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
}
|
||||
}
|
||||
|
||||
assertCreatingPlacement := func(name string, noc *int32, nod int) {
|
||||
ginkgo.By("Create placement")
|
||||
placement := &clusterapiv1alpha1.Placement{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
},
|
||||
Spec: clusterapiv1alpha1.PlacementSpec{
|
||||
NumberOfClusters: noc,
|
||||
},
|
||||
}
|
||||
placement, err = clusterClient.ClusterV1alpha1().Placements(namespace).Create(context.Background(), placement, metav1.CreateOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
assertPlacementDecisionCreated(placement)
|
||||
assertNumberOfDecisions(placementName, nod)
|
||||
if noc != nil {
|
||||
assertPlacementStatus(placementName, nod, nod == int(*noc))
|
||||
}
|
||||
}
|
||||
|
||||
ginkgo.It("Should schedule successfully", func() {
|
||||
assertBindingClusterSet(clusterSet1Name)
|
||||
assertCreatingClusters(clusterSet1Name, 5)
|
||||
assertCreatingPlacement(placementName, noc(10), 5)
|
||||
|
||||
ginkgo.By("Reduce NOC of the placement")
|
||||
placement, err := clusterClient.ClusterV1alpha1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
noc := int32(6)
|
||||
placement.Spec.NumberOfClusters = &noc
|
||||
placement, err = clusterClient.ClusterV1alpha1().Placements(namespace).Update(context.Background(), placement, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
assertNumberOfDecisions(placementName, 5)
|
||||
assertPlacementStatus(placementName, 5, false)
|
||||
|
||||
ginkgo.By("Delete placement")
|
||||
err = clusterClient.ClusterV1alpha1().Placements(namespace).Delete(context.TODO(), placementName, metav1.DeleteOptions{})
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
|
||||
ginkgo.By("Check if placementdecisions are deleted as well")
|
||||
gomega.Eventually(func() bool {
|
||||
placementDecisions, err := clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", placementLabel, placementName),
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return len(placementDecisions.Items) == 0
|
||||
}, eventuallyTimeout*5, eventuallyInterval*5).Should(gomega.BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
func noc(n int) *int32 {
|
||||
noc := int32(n)
|
||||
return &noc
|
||||
}
|
||||
47
test/e2e/suite_test.go
Normal file
47
test/e2e/suite_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
ginkgo "github.com/onsi/ginkgo"
|
||||
gomega "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
clusterclient "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
)
|
||||
|
||||
const (
|
||||
eventuallyTimeout = 30 // seconds
|
||||
eventuallyInterval = 1 // seconds
|
||||
)
|
||||
|
||||
func TestE2E(t *testing.T) {
|
||||
gomega.RegisterFailHandler(ginkgo.Fail)
|
||||
ginkgo.RunSpecs(t, "E2E Suite")
|
||||
}
|
||||
|
||||
var (
|
||||
kubeClient kubernetes.Interface
|
||||
clusterClient clusterclient.Interface
|
||||
restConfig *rest.Config
|
||||
)
|
||||
|
||||
var _ = ginkgo.BeforeSuite(func() {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(ginkgo.GinkgoWriter), zap.UseDevMode(true)))
|
||||
kubeconfig := os.Getenv("KUBECONFIG")
|
||||
|
||||
var err error
|
||||
restConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
kubeClient, err = kubernetes.NewForConfig(restConfig)
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
clusterClient, err = clusterclient.NewForConfig(restConfig)
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
})
|
||||
Reference in New Issue
Block a user