Skip to content

Commit 7fa1954

Browse files
fmountopenshift-merge-bot[bot]
authored andcommitted
Improve topology testing coverage
This patch improves our topology testing with several enhancements and extends the topologyRef tests: - finalizer verification on the referenced topology - Updated Topologies to support component-specific label selectors - assert topologySpecObj at component level instead of just asserting that is not nil This work completes the topology validation improvements initiated in [1], addressing the remaining open points. [1] nova-operator#941 Signed-off-by: Francesco Pantano <[email protected]>
1 parent 4a8d5a2 commit 7fa1954

File tree

2 files changed

+98
-24
lines changed

2 files changed

+98
-24
lines changed

tests/functional/base_test.go

+40-5
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ import (
2424
"k8s.io/apimachinery/pkg/types"
2525
"sigs.k8s.io/controller-runtime/pkg/client"
2626

27+
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
2728
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
2829
placementv1 "github.com/openstack-k8s-operators/placement-operator/api/v1beta1"
2930
"github.com/openstack-k8s-operators/placement-operator/pkg/placement"
31+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3032
)
3133

3234
type Names struct {
@@ -185,7 +187,7 @@ func PlacementConditionGetter(name types.NamespacedName) condition.Conditions {
185187
// want to avoid by default
186188
// 2. Usually a topologySpreadConstraints is used to take care about
187189
// multi AZ, which is not applicable in this context
188-
func GetSampleTopologySpec() map[string]interface{} {
190+
func GetSampleTopologySpec(label string) (map[string]interface{}, []corev1.TopologySpreadConstraint) {
189191
// Build the topology Spec
190192
topologySpec := map[string]interface{}{
191193
"topologySpreadConstraints": []map[string]interface{}{
@@ -195,17 +197,35 @@ func GetSampleTopologySpec() map[string]interface{} {
195197
"whenUnsatisfiable": "ScheduleAnyway",
196198
"labelSelector": map[string]interface{}{
197199
"matchLabels": map[string]interface{}{
198-
"service": placement.ServiceName,
200+
"service": placement.ServiceName,
201+
"topology": label,
199202
},
200203
},
201204
},
202205
},
203206
}
204-
return topologySpec
207+
// Build the topologyObj representation
208+
topologySpecObj := []corev1.TopologySpreadConstraint{
209+
{
210+
MaxSkew: 1,
211+
TopologyKey: corev1.LabelHostname,
212+
WhenUnsatisfiable: corev1.ScheduleAnyway,
213+
LabelSelector: &metav1.LabelSelector{
214+
MatchLabels: map[string]string{
215+
"service": placement.ServiceName,
216+
"topology": label,
217+
},
218+
},
219+
},
220+
}
221+
return topologySpec, topologySpecObj
205222
}
206223

207224
// CreateTopology - Creates a Topology CR based on the spec passed as input
208-
func CreateTopology(topology types.NamespacedName, spec map[string]interface{}) client.Object {
225+
func CreateTopology(
226+
topology types.NamespacedName,
227+
spec map[string]interface{},
228+
) (client.Object, topologyv1.TopoRef) {
209229
raw := map[string]interface{}{
210230
"apiVersion": "topology.openstack.org/v1beta1",
211231
"kind": "Topology",
@@ -215,5 +235,20 @@ func CreateTopology(topology types.NamespacedName, spec map[string]interface{})
215235
},
216236
"spec": spec,
217237
}
218-
return th.CreateUnstructured(raw)
238+
// other than creating the topology based on the raw spec, we return the
239+
// TopoRef that can be referenced
240+
topologyRef := topologyv1.TopoRef{
241+
Name: topology.Name,
242+
Namespace: topology.Namespace,
243+
}
244+
return th.CreateUnstructured(raw), topologyRef
245+
}
246+
247+
// GetTopology - Returns the referenced Topology
248+
func GetTopology(name types.NamespacedName) *topologyv1.Topology {
249+
instance := &topologyv1.Topology{}
250+
Eventually(func(g Gomega) {
251+
g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed())
252+
}, timeout, interval).Should(Succeed())
253+
return instance
219254
}

tests/functional/placementapi_controller_test.go

+58-19
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ import (
2424
. "github.com/onsi/gomega" //revive:disable:dot-imports
2525

2626
//revive:disable-next-line:dot-imports
27+
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
28+
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
29+
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
2730
. "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
31+
mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers"
2832
mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
2933
"github.com/openstack-k8s-operators/placement-operator/pkg/placement"
3034
corev1 "k8s.io/api/core/v1"
3135
"k8s.io/apimachinery/pkg/types"
32-
33-
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
34-
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
35-
mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers"
3636
)
3737

3838
var _ = Describe("PlacementAPI controller", func() {
@@ -880,12 +880,6 @@ var _ = Describe("PlacementAPI controller", func() {
880880

881881
When("A PlacementAPI is created with a wrong topologyref", func() {
882882
BeforeEach(func() {
883-
// Build the topology Spec
884-
topologySpec := GetSampleTopologySpec()
885-
// Create Test Topologies
886-
for _, t := range names.PlacementAPITopologies {
887-
CreateTopology(t, topologySpec)
888-
}
889883
spec := GetDefaultPlacementAPISpec()
890884
spec["topologyRef"] = map[string]interface{}{
891885
"name": "foo",
@@ -914,16 +908,26 @@ var _ = Describe("PlacementAPI controller", func() {
914908
})
915909
})
916910
When("A PlacementAPI is created with topologyref", func() {
911+
var topologyRef, topologyRefAlt *topologyv1.TopoRef
917912
BeforeEach(func() {
918-
// Build the topology Spec
919-
topologySpec := GetSampleTopologySpec()
913+
// Define the two topology references used in this test
914+
topologyRef = &topologyv1.TopoRef{
915+
Name: names.PlacementAPITopologies[0].Name,
916+
Namespace: names.PlacementAPITopologies[0].Namespace,
917+
}
918+
topologyRefAlt = &topologyv1.TopoRef{
919+
Name: names.PlacementAPITopologies[1].Name,
920+
Namespace: names.PlacementAPITopologies[1].Namespace,
921+
}
920922
// Create Test Topologies
921923
for _, t := range names.PlacementAPITopologies {
924+
// Build the topology Spec
925+
topologySpec, _ := GetSampleTopologySpec(t.Name)
922926
CreateTopology(t, topologySpec)
923927
}
924928
spec := GetDefaultPlacementAPISpec()
925929
spec["topologyRef"] = map[string]interface{}{
926-
"name": names.PlacementAPITopologies[0].Name,
930+
"name": topologyRef.Name,
927931
}
928932
placement := CreatePlacementAPI(names.PlacementAPIName, spec)
929933
DeferCleanup(th.DeleteInstance, placement)
@@ -948,9 +952,17 @@ var _ = Describe("PlacementAPI controller", func() {
948952

949953
It("sets topology in CR status", func() {
950954
Eventually(func(g Gomega) {
955+
tp := GetTopology(types.NamespacedName{
956+
Name: topologyRef.Name,
957+
Namespace: topologyRef.Namespace,
958+
})
959+
finalizers := tp.GetFinalizers()
960+
g.Expect(finalizers).To(HaveLen(1))
951961
placement := GetPlacementAPI(names.PlacementAPIName)
952962
g.Expect(placement.Status.LastAppliedTopology).ToNot(BeNil())
953-
g.Expect(placement.Status.LastAppliedTopology.Name).To(Equal(names.PlacementAPITopologies[0].Name))
963+
g.Expect(placement.Status.LastAppliedTopology).To(Equal(topologyRef))
964+
g.Expect(finalizers).To(ContainElement(
965+
fmt.Sprintf("openstack.org/placementapi-%s", names.PlacementAPIName.Name)))
954966
}, timeout, interval).Should(Succeed())
955967

956968
th.ExpectCondition(
@@ -963,23 +975,38 @@ var _ = Describe("PlacementAPI controller", func() {
963975

964976
It("sets topology in resource specs", func() {
965977
Eventually(func(g Gomega) {
966-
g.Expect(th.GetDeployment(names.DeploymentName).Spec.Template.Spec.TopologySpreadConstraints).ToNot(BeNil())
978+
_, topologySpecObj := GetSampleTopologySpec(topologyRef.Name)
967979
g.Expect(th.GetDeployment(names.DeploymentName).Spec.Template.Spec.Affinity).To(BeNil())
980+
g.Expect(th.GetDeployment(names.DeploymentName).Spec.Template.Spec.TopologySpreadConstraints).ToNot(BeNil())
981+
g.Expect(th.GetDeployment(names.DeploymentName).Spec.Template.Spec.TopologySpreadConstraints).To(Equal(topologySpecObj))
968982
}, timeout, interval).Should(Succeed())
969983
})
970984
It("updates topology when the reference changes", func() {
971985
Eventually(func(g Gomega) {
972986
placement := GetPlacementAPI(names.PlacementAPIName)
973-
g.Expect(placement.Status.LastAppliedTopology).ToNot(BeNil())
974-
g.Expect(placement.Status.LastAppliedTopology.Name).To(Equal(names.PlacementAPITopologies[0].Name))
975-
placement.Spec.TopologyRef.Name = names.PlacementAPITopologies[1].Name
987+
placement.Spec.TopologyRef.Name = topologyRefAlt.Name
976988
g.Expect(k8sClient.Update(ctx, placement)).To(Succeed())
977989
}, timeout, interval).Should(Succeed())
978990

979991
Eventually(func(g Gomega) {
992+
tp := GetTopology(types.NamespacedName{
993+
Name: topologyRefAlt.Name,
994+
Namespace: topologyRefAlt.Namespace,
995+
})
996+
finalizers := tp.GetFinalizers()
997+
g.Expect(finalizers).To(HaveLen(1))
980998
placement := GetPlacementAPI(names.PlacementAPIName)
981999
g.Expect(placement.Status.LastAppliedTopology).ToNot(BeNil())
982-
g.Expect(placement.Status.LastAppliedTopology.Name).To(Equal(names.PlacementAPITopologies[1].Name))
1000+
g.Expect(placement.Status.LastAppliedTopology).To(Equal(topologyRefAlt))
1001+
g.Expect(finalizers).To(ContainElement(
1002+
fmt.Sprintf("openstack.org/placementapi-%s", names.PlacementAPIName.Name)))
1003+
// Verify the previous referenced topology has no finalizers
1004+
tp = GetTopology(types.NamespacedName{
1005+
Name: topologyRef.Name,
1006+
Namespace: topologyRef.Namespace,
1007+
})
1008+
finalizers = tp.GetFinalizers()
1009+
g.Expect(finalizers).To(BeEmpty())
9831010
}, timeout, interval).Should(Succeed())
9841011

9851012
th.ExpectCondition(
@@ -1006,6 +1033,18 @@ var _ = Describe("PlacementAPI controller", func() {
10061033
g.Expect(th.GetDeployment(names.DeploymentName).Spec.Template.Spec.TopologySpreadConstraints).To(BeNil())
10071034
g.Expect(th.GetDeployment(names.DeploymentName).Spec.Template.Spec.Affinity).ToNot(BeNil())
10081035
}, timeout, interval).Should(Succeed())
1036+
1037+
// Verify the existing topologies have no finalizer anymore
1038+
Eventually(func(g Gomega) {
1039+
for _, topology := range names.PlacementAPITopologies {
1040+
tp := GetTopology(types.NamespacedName{
1041+
Name: topology.Name,
1042+
Namespace: topology.Namespace,
1043+
})
1044+
finalizers := tp.GetFinalizers()
1045+
g.Expect(finalizers).To(BeEmpty())
1046+
}
1047+
}, timeout, interval).Should(Succeed())
10091048
})
10101049
})
10111050

0 commit comments

Comments
 (0)