You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ho...@apache.org on 2023/09/27 19:58:43 UTC

[solr-operator] branch main updated: Small fixes for integration tests

This is an automated email from the ASF dual-hosted git repository.

houston pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 2694e6a  Small fixes for integration tests
2694e6a is described below

commit 2694e6a1a6db5b305e77a2581514d3c19f844bfa
Author: Houston Putman <ho...@apache.org>
AuthorDate: Mon Sep 25 12:04:06 2023 -0400

    Small fixes for integration tests
---
 controllers/solrcloud_controller.go |  3 ++-
 tests/e2e/resource_utils_test.go    | 19 +++++++++++++++++--
 tests/e2e/solrcloud_scaling_test.go | 13 ++++++++-----
 tests/e2e/test_utils_test.go        | 25 ++++++++++++-------------
 4 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/controllers/solrcloud_controller.go b/controllers/solrcloud_controller.go
index e586e77..6bd81e8 100644
--- a/controllers/solrcloud_controller.go
+++ b/controllers/solrcloud_controller.go
@@ -385,7 +385,8 @@ func (r *SolrCloudReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
 			if err = controllerutil.SetControllerReference(instance, expectedStatefulSet, r.Scheme); err == nil {
 				err = r.Create(ctx, expectedStatefulSet)
 			}
-			statefulSet = expectedStatefulSet
+			// Wait for the next reconcile loop
+			statefulSet = nil
 		} else if err == nil {
 			util.MaintainPreservedStatefulSetFields(expectedStatefulSet, foundStatefulSet)
 
diff --git a/tests/e2e/resource_utils_test.go b/tests/e2e/resource_utils_test.go
index a41770b..fc7a998 100644
--- a/tests/e2e/resource_utils_test.go
+++ b/tests/e2e/resource_utils_test.go
@@ -68,14 +68,14 @@ func deleteAndWait(ctx context.Context, object client.Object, additionalOffset .
 
 func expectSolrCloudToBeReady(ctx context.Context, solrCloud *solrv1beta1.SolrCloud, additionalOffset ...int) *solrv1beta1.SolrCloud {
 	return expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-		g.Expect(found.Status.ReadyReplicas).To(Equal(*found.Spec.Replicas), "The SolrCloud should have all nodes come up healthy")
+		g.Expect(found.Status.ReadyReplicas).To(Equal(*solrCloud.Spec.Replicas), "The SolrCloud should have all nodes come up healthy")
 		// We have to check the status.replicas, because when a cloud is deleted/recreated, the statefulset can be recreated
 		// before the pods of the previous statefulset are deleted. So those pods will still be matched to the label selector,
 		// but the new statefulset doesn't know about them.
 		// The "Status.ReadyReplicas" value is populated from querying with the label selector
 		// The "Status.Replicas" value is populated from the statefulSet status
 		// So we need both to be equal to the requested number of replicas in order to know the statefulset is ready to go.
-		g.Expect(found.Status.Replicas).To(Equal(*found.Spec.Replicas), "The SolrCloud should have all nodes come up healthy")
+		g.Expect(found.Status.Replicas).To(Equal(*solrCloud.Spec.Replicas), "The SolrCloud should have all nodes come up healthy")
 	}, resolveOffset(additionalOffset))
 }
 
@@ -255,6 +255,21 @@ func expectStatefulSetWithChecks(ctx context.Context, parentResource client.Obje
 	return statefulSet
 }
 
+func expectStatefulSetWithChecksAndTimeout(ctx context.Context, parentResource client.Object, statefulSetName string, within time.Duration, checkEvery time.Duration, additionalChecks func(Gomega, *appsv1.StatefulSet), additionalOffset ...int) *appsv1.StatefulSet {
+	statefulSet := &appsv1.StatefulSet{}
+	EventuallyWithOffset(resolveOffset(additionalOffset), func(g Gomega) {
+		g.Expect(k8sClient.Get(ctx, resourceKey(parentResource, statefulSetName), statefulSet)).To(Succeed(), "Expected StatefulSet does not exist")
+
+		testMapContainsOtherWithGomega(g, "StatefulSet pod template selector", statefulSet.Spec.Template.Labels, statefulSet.Spec.Selector.MatchLabels)
+		g.Expect(len(statefulSet.Spec.Selector.MatchLabels)).To(BeNumerically(">=", 1), "StatefulSet pod template selector must have at least 1 label")
+
+		if additionalChecks != nil {
+			additionalChecks(g, statefulSet)
+		}
+	}).Within(within).WithPolling(checkEvery).Should(Succeed())
+	return statefulSet
+}
+
 func expectStatefulSetWithConsistentChecks(ctx context.Context, parentResource client.Object, statefulSetName string, additionalChecks func(Gomega, *appsv1.StatefulSet), additionalOffset ...int) *appsv1.StatefulSet {
 	statefulSet := &appsv1.StatefulSet{}
 	ConsistentlyWithOffset(resolveOffset(additionalOffset), func(g Gomega) {
diff --git a/tests/e2e/solrcloud_scaling_test.go b/tests/e2e/solrcloud_scaling_test.go
index d3a0868..1fa3890 100644
--- a/tests/e2e/solrcloud_scaling_test.go
+++ b/tests/e2e/solrcloud_scaling_test.go
@@ -26,6 +26,7 @@ import (
 	appsv1 "k8s.io/api/apps/v1"
 	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	"time"
 )
 
 var _ = FDescribe("E2E - SolrCloud - Scale Down", func() {
@@ -120,13 +121,15 @@ var _ = FDescribe("E2E - SolrCloud - Scale Down", func() {
 			Expect(clusterOp.Metadata).To(Equal("1"), "StatefulSet scaling lock operation has the wrong metadata.")
 
 			// Wait for the last pod to be deleted
-			statefulSet = expectStatefulSetWithChecks(ctx, solrCloud, solrCloud.StatefulSetName(), func(g Gomega, found *appsv1.StatefulSet) {
+			expectStatefulSetWithChecks(ctx, solrCloud, solrCloud.StatefulSetName(), func(g Gomega, found *appsv1.StatefulSet) {
 				g.Expect(found.Status.Replicas).To(HaveValue(BeEquivalentTo(1)), "StatefulSet should now have 1 pods, after the replicas have been moved.")
 			})
-			// Once the scale down actually occurs, the statefulSet annotations should already be removed
-			clusterOp, err = controllers.GetCurrentClusterOp(statefulSet)
-			Expect(err).ToNot(HaveOccurred(), "Error occurred while finding clusterLock for SolrCloud")
-			Expect(clusterOp).To(BeNil(), "StatefulSet should not have a ScaleDown lock after scaling is complete.")
+			// Once the scale down actually occurs, the statefulSet annotations should be removed very soon
+			expectStatefulSetWithChecksAndTimeout(ctx, solrCloud, solrCloud.StatefulSetName(), time.Second*2, time.Millisecond*500, func(g Gomega, found *appsv1.StatefulSet) {
+				clusterOp, err = controllers.GetCurrentClusterOp(found)
+				g.Expect(err).ToNot(HaveOccurred(), "Error occurred while finding clusterLock for SolrCloud")
+				g.Expect(clusterOp).To(BeNil(), "StatefulSet should not have a ScaleDown lock after scaling is complete.")
+			})
 
 			expectNoPod(ctx, solrCloud, solrCloud.GetSolrPodName(1))
 			queryCollection(ctx, solrCloud, solrCollection1, 0)
diff --git a/tests/e2e/test_utils_test.go b/tests/e2e/test_utils_test.go
index 4e1db8f..b28df88 100644
--- a/tests/e2e/test_utils_test.go
+++ b/tests/e2e/test_utils_test.go
@@ -34,6 +34,7 @@ import (
 	"helm.sh/helm/v3/pkg/cli"
 	"helm.sh/helm/v3/pkg/release"
 	"helm.sh/helm/v3/pkg/storage/driver"
+	"io"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -432,7 +433,7 @@ func checkBackupWithGomega(ctx context.Context, solrCloud *solrv1beta1.SolrCloud
 			innerG.Expect(err).ToNot(HaveOccurred(), "Error occurred while fetching backup '%s' for collection '%s': %s", solrBackup.Name, collection, backupParams)
 			backupListResponse := &solr_api.SolrBackupListResponse{}
 
-			innerG.Expect(json.Unmarshal([]byte(response), &backupListResponse)).To(Succeed(), "Could not parse json from Solr BackupList API")
+			innerG.Expect(json.Unmarshal([]byte(response), &backupListResponse)).To(Succeed(), "Could not parse json from Solr BackupList API: %s", response)
 
 			innerG.Expect(backupListResponse.ResponseHeader.Status).To(BeZero(), "SolrBackupList API returned exception code: %d", backupListResponse.ResponseHeader.Status)
 			checks(innerG, collection, backupListResponse)
@@ -455,7 +456,7 @@ func (r *ExecError) Error() string {
 }
 
 func callSolrApiInPod(ctx context.Context, solrCloud *solrv1beta1.SolrCloud, httpMethod string, apiPath string, queryParams map[string]string, hostnameOptional ...string) (response string, err error) {
-	hostname := "${POD_NAME}"
+	hostname := "${SOLR_HOST}"
 	if len(hostnameOptional) > 0 {
 		hostname = hostnameOptional[0]
 	}
@@ -511,28 +512,26 @@ func runExecForContainer(ctx context.Context, container string, podName string,
 		return "", fmt.Errorf("error while creating Executor: %v", err)
 	}
 
-	var stdout, stderr bytes.Buffer
+	var combined, stdout, stderr bytes.Buffer
 	err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{
-		Stdout: &stdout,
-		Stderr: &stderr,
+		Stdout: io.MultiWriter(&stdout, &combined),
+		Stderr: io.MultiWriter(&stderr, &combined),
 		Tty:    false,
 	})
 
-	responseOutput := stdout.String()
-	errOutput := stderr.String()
+	response = combined.String()
 
 	if err != nil {
 		err = &ExecError{
 			Command:        strings.Join(command, " "),
 			Err:            err,
-			ResponseOutput: responseOutput,
-			ErrorOutput:    errOutput,
+			ResponseOutput: stdout.String(),
+			ErrorOutput:    stderr.String(),
 		}
-	}
-	if len(responseOutput) == 0 {
-		response = errOutput
+
+		response = combined.String()
 	} else {
-		response = responseOutput
+		response = stdout.String()
 	}
 
 	return response, err