Skip to content

Commit

Permalink
Merge pull request #1448 from Nordix/e2e-helper-functions/max
Browse files Browse the repository at this point in the history
🌱 Implement Helper Functions for E2E Tests
  • Loading branch information
metal3-io-bot committed Nov 22, 2023
2 parents 47a68b9 + 11c53b5 commit 21384d9
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 125 deletions.
16 changes: 3 additions & 13 deletions test/e2e/basic_ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
var _ = Describe("basic", func() {
var (
specName = "basic-ops"
secretName = "bmc-credentials"
namespace *corev1.Namespace
cancelWatches context.CancelFunc
bmcUser string
Expand Down Expand Up @@ -47,18 +48,7 @@ var _ = Describe("basic", func() {

It("should control power cycle of BMH though annotations", func() {
By("creating a secret with BMH credentials")
bmcCredentials := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bmc-credentials",
Namespace: namespace.Name,
},
StringData: map[string]string{
"username": bmcUser,
"password": bmcPassword,
},
}
err := clusterProxy.GetClient().Create(ctx, &bmcCredentials)
Expect(err).NotTo(HaveOccurred())
CreateBMHCredentialsSecret(ctx, clusterProxy.GetClient(), namespace.Name, secretName, bmcUser, bmcPassword)

By("creating a BMH")
bmh := metal3api.BareMetalHost{
Expand All @@ -79,7 +69,7 @@ var _ = Describe("basic", func() {
BootMACAddress: bootMacAddress,
},
}
err = clusterProxy.GetClient().Create(ctx, &bmh)
err := clusterProxy.GetClient().Create(ctx, &bmh)
Expect(err).NotTo(HaveOccurred())

By("waiting for the BMH to become available")
Expand Down
97 changes: 28 additions & 69 deletions test/e2e/basic_provisioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import (
"sigs.k8s.io/cluster-api/test/framework"
"sigs.k8s.io/cluster-api/util"
"sigs.k8s.io/cluster-api/util/patch"
"sigs.k8s.io/controller-runtime/pkg/client"

metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
)

var _ = Describe("BMH Provisioning and Annotation Management", func() {
var (
specName = "provisioning-ops"
secretName = "bmc-credentials"
namespace *corev1.Namespace
cancelWatches context.CancelFunc
bmcUser string
Expand All @@ -47,18 +47,7 @@ var _ = Describe("BMH Provisioning and Annotation Management", func() {

It("provisions a BMH, applies detached and status annotations, then deprovisions", func() {
By("Creating a secret with BMH credentials")
bmcCredentials := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bmc-credentials",
Namespace: namespace.Name,
},
StringData: map[string]string{
"username": bmcUser,
"password": bmcPassword,
},
}
err := clusterProxy.GetClient().Create(ctx, &bmcCredentials)
Expect(err).NotTo(HaveOccurred())
CreateBMHCredentialsSecret(ctx, clusterProxy.GetClient(), namespace.Name, secretName, bmcUser, bmcPassword)

By("Creating a BMH with inspection disabled and hardware details added")
bmh := metal3api.BareMetalHost{
Expand All @@ -80,7 +69,7 @@ var _ = Describe("BMH Provisioning and Annotation Management", func() {
BootMACAddress: bootMacAddress,
},
}
err = clusterProxy.GetClient().Create(ctx, &bmh)
err := clusterProxy.GetClient().Create(ctx, &bmh)
Expect(err).NotTo(HaveOccurred())

By("Waiting for the BMH to become available")
Expand Down Expand Up @@ -117,7 +106,7 @@ var _ = Describe("BMH Provisioning and Annotation Management", func() {
}, e2eConfig.GetIntervals(specName, "wait-provisioned")...)

By("Retrieving the latest BMH object")
err = clusterProxy.GetClient().Get(ctx, client.ObjectKey{
err = clusterProxy.GetClient().Get(ctx, types.NamespacedName{
Name: bmh.Name,
Namespace: bmh.Namespace,
}, &bmh)
Expand Down Expand Up @@ -146,53 +135,28 @@ var _ = Describe("BMH Provisioning and Annotation Management", func() {
Expect(err).NotTo(HaveOccurred())

By("Waiting for the BMH to be deleted")
Eventually(func() (string, error) {
var currentBmh metal3api.BareMetalHost
err := clusterProxy.GetClient().Get(ctx, types.NamespacedName{Name: bmh.Name, Namespace: bmh.Namespace}, &currentBmh)
if err != nil {
if apierrors.IsNotFound(err) {
// If the BMH is not found, we assume it has been successfully deleted.
return "deleted", nil
}
// Any other error should be returned.
return "", err
}

currentStatus := currentBmh.Status.Provisioning.State

// If the state is 'deleting' or 'provisioned', we continue polling.
if currentStatus == "deleting" || currentStatus == "provisioned" {
return string(currentStatus), nil
}

// Any other state is unexpected, and we stop the polling.
return "", StopTrying(fmt.Sprintf("BMH is in an unexpected state: %s", currentStatus))
}, e2eConfig.GetIntervals(specName, "wait-deleted")...).Should(Equal("deleted"))
WaitForBmhDeleted(ctx, WaitForBmhDeletedInput{
Client: clusterProxy.GetClient(),
BmhName: bmh.Name,
Namespace: bmh.Namespace,
UndesiredStates: []metal3api.ProvisioningState{
metal3api.StateProvisioning,
metal3api.StateRegistering,
metal3api.StateDeprovisioning,
},
}, e2eConfig.GetIntervals(specName, "wait-deleted")...)

By("Waiting for the secret to be deleted")
Eventually(func() bool {
err := clusterProxy.GetClient().Get(ctx, client.ObjectKey{
err := clusterProxy.GetClient().Get(ctx, types.NamespacedName{
Name: "bmc-credentials",
Namespace: namespace.Name,
}, &corev1.Secret{})
return apierrors.IsNotFound(err)
}, e2eConfig.GetIntervals(specName, "wait-secret-deletion")...).Should(BeTrue())

By("Creating a secret with BMH credentials")
secretName := "bmc-credentials"
bmcCredentials = corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace.Name,
},
StringData: map[string]string{
"username": bmcUser,
"password": bmcPassword,
},
}

err = clusterProxy.GetClient().Create(ctx, &bmcCredentials)
Expect(err).NotTo(HaveOccurred())
CreateBMHCredentialsSecret(ctx, clusterProxy.GetClient(), namespace.Name, secretName, bmcUser, bmcPassword)

By("Recreating the BMH with the previously saved status in the status annotation")
bmh = metal3api.BareMetalHost{
Expand Down Expand Up @@ -225,23 +189,17 @@ var _ = Describe("BMH Provisioning and Annotation Management", func() {
Expect(err).NotTo(HaveOccurred())

By("Checking that the BMH goes directly to 'provisioned' state")
Eventually(func() (string, error) {
var currentBmh metal3api.BareMetalHost
err := clusterProxy.GetClient().Get(ctx, types.NamespacedName{Name: bmh.Name, Namespace: bmh.Namespace}, &currentBmh)
if err != nil {
// Handle errors that may occur while fetching the BMH.
return "", err
}

currentStatus := currentBmh.Status.Provisioning.State

if currentStatus == "provisioned" || currentStatus == "" {
return string(currentStatus), nil
}

// Any other state is unexpected, and we stop the polling.
return "", StopTrying(fmt.Sprintf("BMH should not be in '%s' state", currentStatus))
}, e2eConfig.GetIntervals(specName, "wait-provisioned")...).Should(Equal("provisioned"))
WaitForBmhInProvisioningState(ctx, WaitForBmhInProvisioningStateInput{
Client: clusterProxy.GetClient(),
Bmh: bmh,
State: metal3api.StateProvisioned,
UndesiredStates: []metal3api.ProvisioningState{
metal3api.StateProvisioning,
metal3api.StateRegistering,
metal3api.StateDeprovisioning,
metal3api.StateDeleting,
},
}, e2eConfig.GetIntervals(specName, "wait-provisioned")...)

By("Triggering the deprovisioning of the BMH")
helper, err = patch.NewHelper(&bmh, clusterProxy.GetClient())
Expand All @@ -262,6 +220,7 @@ var _ = Describe("BMH Provisioning and Annotation Management", func() {
Bmh: bmh,
State: metal3api.StateAvailable,
}, e2eConfig.GetIntervals(specName, "wait-available")...)

})

AfterEach(func() {
Expand Down
83 changes: 79 additions & 4 deletions test/e2e/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"

Expand Down Expand Up @@ -153,21 +154,75 @@ func (c *Config) GetVariable(varName string) string {
return value
}

func isUndesiredState(currentState metal3api.ProvisioningState, undesiredStates []metal3api.ProvisioningState) bool {
if undesiredStates == nil {
return false
}

for _, state := range undesiredStates {
if (state == "" && currentState == "") || currentState == state {
return true
}
}
return false
}

type WaitForBmhInProvisioningStateInput struct {
Client client.Client
Bmh metal3api.BareMetalHost
State metal3api.ProvisioningState
Client client.Client
Bmh metal3api.BareMetalHost
State metal3api.ProvisioningState
UndesiredStates []metal3api.ProvisioningState
}

func WaitForBmhInProvisioningState(ctx context.Context, input WaitForBmhInProvisioningStateInput, intervals ...interface{}) {
Eventually(func(g Gomega) {
bmh := metal3api.BareMetalHost{}
key := types.NamespacedName{Namespace: input.Bmh.Namespace, Name: input.Bmh.Name}
g.Expect(input.Client.Get(ctx, key, &bmh)).To(Succeed())
g.Expect(bmh.Status.Provisioning.State).To(Equal(input.State))

currentStatus := bmh.Status.Provisioning.State

// Check if the current state matches any of the undesired states
if isUndesiredState(currentStatus, input.UndesiredStates) {
StopTrying(fmt.Sprintf("BMH is in an unexpected state: %s", currentStatus)).Now()
}

g.Expect(currentStatus).To(Equal(input.State))
}, intervals...).Should(Succeed())
}

// WaitForBmhDeletedInput is the input for WaitForBmhDeleted.
type WaitForBmhDeletedInput struct {
Client client.Client
BmhName string
Namespace string
UndesiredStates []metal3api.ProvisioningState
}

// WaitForBmhDeleted waits until the BMH object has been deleted.
func WaitForBmhDeleted(ctx context.Context, input WaitForBmhDeletedInput, intervals ...interface{}) {
Eventually(func(g Gomega) bool {
bmh := &metal3api.BareMetalHost{}
key := types.NamespacedName{Namespace: input.Namespace, Name: input.BmhName}
err := input.Client.Get(ctx, key, bmh)

// If BMH is not found, it's considered deleted, which is the desired outcome.
if apierrors.IsNotFound(err) {
return true
}
g.Expect(err).NotTo(HaveOccurred())

currentStatus := bmh.Status.Provisioning.State

// If the BMH is found, check for undesired states.
if isUndesiredState(currentStatus, input.UndesiredStates) {
StopTrying(fmt.Sprintf("BMH is in an unexpected state: %s", currentStatus)).Now()
}

return false
}, intervals...).Should(BeTrue(), fmt.Sprintf("BMH %s in namespace %s should be deleted", input.BmhName, input.Namespace))
}

// WaitForNamespaceDeletedInput is the input for WaitForNamespaceDeleted.
type WaitForNamespaceDeletedInput struct {
Getter framework.Getter
Expand Down Expand Up @@ -221,3 +276,23 @@ func buildKustomizeManifest(source string) ([]byte, error) {
}
return resources.AsYaml()
}

func CreateBMHCredentialsSecret(ctx context.Context, client client.Client, secretNamespace, secretName, username, password string) error {
bmcCredentials := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: secretNamespace,
},
StringData: map[string]string{
"username": username,
"password": password,
},
}

err := client.Create(ctx, &bmcCredentials)
if err != nil {
return fmt.Errorf("failed to create BMC credentials secret: %w", err)
}

return nil
}
1 change: 1 addition & 0 deletions test/e2e/config/fixture.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ intervals:
default/wait-deprovisioning: ["5s", "10ms"]
default/wait-available: ["20s", "1s"]
default/wait-deleting: ["5s", "10ms"]
default/wait-deleted: ["5s", "10ms"]
default/wait-secret-deletion: ["5s", "10ms"]
16 changes: 3 additions & 13 deletions test/e2e/external_inspection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ const hardwareDetails = `
var _ = Describe("External Inspection", func() {
var (
specName = "external-inspection"
secretName = "bmc-credentials"
namespace *corev1.Namespace
cancelWatches context.CancelFunc
bmcUser string
Expand All @@ -197,18 +198,7 @@ var _ = Describe("External Inspection", func() {

It("should skip inspection and become available when a BMH has annotations with hardware details and inspection disabled", func() {
By("creating a secret with BMH credentials")
bmcCredentials := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bmc-credentials",
Namespace: namespace.Name,
},
StringData: map[string]string{
"username": bmcUser,
"password": bmcPassword,
},
}
err := clusterProxy.GetClient().Create(ctx, &bmcCredentials)
Expect(err).NotTo(HaveOccurred())
CreateBMHCredentialsSecret(ctx, clusterProxy.GetClient(), namespace.Name, secretName, bmcUser, bmcPassword)

By("creating a BMH with inspection disabled and hardware details added")
bmh := metal3api.BareMetalHost{
Expand All @@ -229,7 +219,7 @@ var _ = Describe("External Inspection", func() {
BootMACAddress: bootMacAddress,
},
}
err = clusterProxy.GetClient().Create(ctx, &bmh)
err := clusterProxy.GetClient().Create(ctx, &bmh)
Expect(err).NotTo(HaveOccurred())

By("waiting for the BMH to become available")
Expand Down
16 changes: 3 additions & 13 deletions test/e2e/inspection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
var _ = Describe("Inspection", func() {
var (
specName = "inspection"
secretName = "bmc-credentials"
namespace *corev1.Namespace
cancelWatches context.CancelFunc
bmcUser string
Expand Down Expand Up @@ -92,18 +93,7 @@ var _ = Describe("Inspection", func() {

It("should inspect a newly created BMH", func() {
By("creating a secret with BMH credentials")
bmcCredentials := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bmc-credentials",
Namespace: namespace.Name,
},
StringData: map[string]string{
"username": bmcUser,
"password": bmcPassword,
},
}
err := clusterProxy.GetClient().Create(ctx, &bmcCredentials)
Expect(err).NotTo(HaveOccurred())
CreateBMHCredentialsSecret(ctx, clusterProxy.GetClient(), namespace.Name, secretName, bmcUser, bmcPassword)

By("creating a BMH")
bmh := metal3api.BareMetalHost{
Expand All @@ -120,7 +110,7 @@ var _ = Describe("Inspection", func() {
BootMACAddress: bootMacAddress,
},
}
err = clusterProxy.GetClient().Create(ctx, &bmh)
err := clusterProxy.GetClient().Create(ctx, &bmh)
Expect(err).NotTo(HaveOccurred())

By("waiting for the BMH to be in inspecting state")
Expand Down
Loading

0 comments on commit 21384d9

Please sign in to comment.