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 720285a  Use DeferCleanup() and a sharedZK in e2e tests (#562)
720285a is described below

commit 720285aaf891d95d461adf77189bac0d7011c9e2
Author: Houston Putman <[email protected]>
AuthorDate: Wed Apr 26 11:30:03 2023 -0400

    Use DeferCleanup() and a sharedZK in e2e tests (#562)
    
    Overall just making the e2e tests cleaner and faster.
---
 api/v1beta1/solrcloud_types.go              |   4 +
 tests/e2e/backups_test.go                   |  62 ++++---------
 tests/e2e/prometheus_exporter_test.go       |  51 ++---------
 tests/e2e/resource_utils_test.go            |  29 ++++++
 tests/e2e/solrcloud_basic_test.go           |  74 +++++++++++++++
 tests/e2e/solrcloud_rolling_upgrade_test.go |  44 ++-------
 tests/e2e/suite_test.go                     |  67 +++++++-------
 tests/e2e/test_utils_test.go                | 134 ++++++++++++++++++++++++++--
 8 files changed, 293 insertions(+), 172 deletions(-)

diff --git a/api/v1beta1/solrcloud_types.go b/api/v1beta1/solrcloud_types.go
index f78d3a0..8c9145c 100644
--- a/api/v1beta1/solrcloud_types.go
+++ b/api/v1beta1/solrcloud_types.go
@@ -1211,6 +1211,10 @@ func (sc *SolrCloud) GetAllSolrPodNames() []string {
        return podNames
 }
 
+func (sc *SolrCloud) GetSolrPodName(podNumber int) string {
+       return fmt.Sprintf("%s-%d", sc.StatefulSetName(), podNumber)
+}
+
 func (sc *SolrCloud) BasicAuthSecretName() string {
        if sc.Spec.SolrSecurity != nil && sc.Spec.SolrSecurity.BasicAuthSecret 
!= "" {
                return sc.Spec.SolrSecurity.BasicAuthSecret
diff --git a/tests/e2e/backups_test.go b/tests/e2e/backups_test.go
index 3f0a95b..3188bf7 100644
--- a/tests/e2e/backups_test.go
+++ b/tests/e2e/backups_test.go
@@ -25,10 +25,8 @@ import (
        . "github.com/onsi/gomega"
        . "github.com/onsi/gomega/gstruct"
        corev1 "k8s.io/api/core/v1"
-       "k8s.io/apimachinery/pkg/api/resource"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/util/rand"
-       "strings"
        "time"
 )
 
@@ -47,44 +45,14 @@ var _ = FDescribe("E2E - Backups", Ordered, func() {
                Create a single SolrCloud that all PrometheusExporter tests in 
this "Describe" will use.
        */
        BeforeAll(func(ctx context.Context) {
-               solrCloud = &solrv1beta1.SolrCloud{
-                       ObjectMeta: metav1.ObjectMeta{
-                               Name:      "foo",
-                               Namespace: testNamespace(),
-                       },
-                       Spec: solrv1beta1.SolrCloudSpec{
-                               Replicas: &two,
-                               SolrImage: &solrv1beta1.ContainerImage{
-                                       Repository: strings.Split(solrImage, 
":")[0],
-                                       Tag:        
strings.Split(solrImage+":", ":")[1],
-                                       PullPolicy: corev1.PullIfNotPresent,
-                               },
-                               ZookeeperRef: &solrv1beta1.ZookeeperRef{
-                                       ProvidedZookeeper: 
&solrv1beta1.ZookeeperSpec{
-                                               Replicas:  &one,
-                                               Ephemeral: 
&solrv1beta1.ZKEphemeral{},
-                                       },
-                               },
-                               SolrJavaMem: "-Xms512m -Xmx512m",
-                               CustomSolrKubeOptions: 
solrv1beta1.CustomSolrKubeOptions{
-                                       PodOptions: &solrv1beta1.PodOptions{
-                                               Resources: 
corev1.ResourceRequirements{
-                                                       Requests: 
corev1.ResourceList{
-                                                               
corev1.ResourceMemory: resource.MustParse("600Mi"),
-                                                               
corev1.ResourceCPU:    resource.MustParse("1"),
-                                                       },
-                                               },
-                                       },
-                               },
-                               BackupRepositories: 
[]solrv1beta1.SolrBackupRepository{
-                                       {
-                                               Name: localBackupRepository,
-                                               Volume: 
&solrv1beta1.VolumeRepository{
-                                                       Source: 
corev1.VolumeSource{
-                                                               HostPath: 
&corev1.HostPathVolumeSource{
-                                                                       Path: 
backupDirHostPath,
-                                                               },
-                                                       },
+               solrCloud = generateBaseSolrCloud(2)
+               solrCloud.Spec.BackupRepositories = 
[]solrv1beta1.SolrBackupRepository{
+                       {
+                               Name: localBackupRepository,
+                               Volume: &solrv1beta1.VolumeRepository{
+                                       Source: corev1.VolumeSource{
+                                               HostPath: 
&corev1.HostPathVolumeSource{
+                                                       Path: backupDirHostPath,
                                                },
                                        },
                                },
@@ -94,6 +62,10 @@ var _ = FDescribe("E2E - Backups", Ordered, func() {
                By("creating the SolrCloud")
                Expect(k8sClient.Create(ctx, solrCloud)).To(Succeed())
 
+               DeferCleanup(func(ctx context.Context) {
+                       cleanupTest(ctx, solrCloud)
+               })
+
                By("Waiting for the SolrCloud to come up healthy")
                solrCloud = 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")
@@ -127,14 +99,10 @@ var _ = FDescribe("E2E - Backups", Ordered, func() {
 
                By("creating a SolrBackup")
                Expect(k8sClient.Create(ctx, solrBackup)).To(Succeed())
-       })
 
-       AfterAll(func(ctx context.Context) {
-               cleanupTest(ctx, solrCloud)
-       })
-
-       AfterEach(func(ctx context.Context) {
-               deleteAndWait(ctx, solrBackup)
+               DeferCleanup(func(ctx context.Context) {
+                       deleteAndWait(ctx, solrBackup)
+               })
        })
 
        FContext("Local Directory - Recurring", func() {
diff --git a/tests/e2e/prometheus_exporter_test.go 
b/tests/e2e/prometheus_exporter_test.go
index 67b1932..e5d840c 100644
--- a/tests/e2e/prometheus_exporter_test.go
+++ b/tests/e2e/prometheus_exporter_test.go
@@ -22,10 +22,7 @@ import (
        solrv1beta1 "github.com/apache/solr-operator/api/v1beta1"
        . "github.com/onsi/ginkgo/v2"
        . "github.com/onsi/gomega"
-       corev1 "k8s.io/api/core/v1"
-       "k8s.io/apimachinery/pkg/api/resource"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "strings"
 )
 
 /*
@@ -46,41 +43,15 @@ var _ = FDescribe("E2E - Prometheus Exporter", Ordered, 
func() {
                Create a single SolrCloud that all PrometheusExporter tests in 
this "Describe" will use.
        */
        BeforeAll(func(ctx context.Context) {
-               solrCloud = &solrv1beta1.SolrCloud{
-                       ObjectMeta: metav1.ObjectMeta{
-                               Name:      "foo",
-                               Namespace: testNamespace(),
-                       },
-                       Spec: solrv1beta1.SolrCloudSpec{
-                               Replicas: &two,
-                               SolrImage: &solrv1beta1.ContainerImage{
-                                       Repository: strings.Split(solrImage, 
":")[0],
-                                       Tag:        
strings.Split(solrImage+":", ":")[1],
-                                       PullPolicy: corev1.PullIfNotPresent,
-                               },
-                               ZookeeperRef: &solrv1beta1.ZookeeperRef{
-                                       ProvidedZookeeper: 
&solrv1beta1.ZookeeperSpec{
-                                               Replicas:  &one,
-                                               Ephemeral: 
&solrv1beta1.ZKEphemeral{},
-                                       },
-                               },
-                               SolrJavaMem: "-Xms512m -Xmx512m",
-                               CustomSolrKubeOptions: 
solrv1beta1.CustomSolrKubeOptions{
-                                       PodOptions: &solrv1beta1.PodOptions{
-                                               Resources: 
corev1.ResourceRequirements{
-                                                       Requests: 
corev1.ResourceList{
-                                                               
corev1.ResourceMemory: resource.MustParse("600Mi"),
-                                                               
corev1.ResourceCPU:    resource.MustParse("1"),
-                                                       },
-                                               },
-                                       },
-                               },
-                       },
-               }
+               solrCloud = generateBaseSolrCloud(2)
 
                By("creating the SolrCloud")
                Expect(k8sClient.Create(ctx, solrCloud)).To(Succeed())
 
+               DeferCleanup(func(ctx context.Context) {
+                       cleanupTest(ctx, solrCloud)
+               })
+
                By("waiting for the SolrCloud to come up healthy")
                solrCloud = 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")
@@ -104,6 +75,10 @@ var _ = FDescribe("E2E - Prometheus Exporter", Ordered, 
func() {
                By("creating a SolrPrometheusExporter")
                Expect(k8sClient.Create(ctx, 
solrPrometheusExporter)).To(Succeed())
 
+               DeferCleanup(func(ctx context.Context) {
+                       deleteAndWait(ctx, solrPrometheusExporter)
+               })
+
                By("waiting for the SolrPrometheusExporter to come up healthy")
                solrPrometheusExporter = 
expectSolrPrometheusExporterWithChecks(ctx, solrPrometheusExporter, func(g 
Gomega, found *solrv1beta1.SolrPrometheusExporter) {
                        g.Expect(found.Status.Ready).To(BeTrue(), "The 
SolrPrometheusExporter should come up healthy")
@@ -113,14 +88,6 @@ var _ = FDescribe("E2E - Prometheus Exporter", Ordered, 
func() {
                checkMetrics(ctx, solrPrometheusExporter, solrCloud, 
solrCollection)
        })
 
-       AfterEach(func(ctx context.Context) {
-               deleteAndWait(ctx, solrPrometheusExporter)
-       })
-
-       AfterAll(func(ctx context.Context) {
-               cleanupTest(ctx, solrCloud)
-       })
-
        FContext("Default - Solr Reference", func() {
                BeforeEach(func() {
                        solrPrometheusExporter.Spec.SolrReference = 
solrv1beta1.SolrReference{
diff --git a/tests/e2e/resource_utils_test.go b/tests/e2e/resource_utils_test.go
index 87d3ada..71aa698 100644
--- a/tests/e2e/resource_utils_test.go
+++ b/tests/e2e/resource_utils_test.go
@@ -177,6 +177,35 @@ func expectSolrBackupWithConsistentChecks(ctx 
context.Context, solrBackup *solrv
        return foundSolrBackup
 }
 
+func expectZookeeperCluster(ctx context.Context, parentResource client.Object, 
zkName string, additionalOffset ...int) *zkApi.ZookeeperCluster {
+       return expectZookeeperClusterWithChecks(ctx, parentResource, zkName, 
nil, resolveOffset(additionalOffset))
+}
+
+func expectZookeeperClusterWithChecks(ctx context.Context, parentResource 
client.Object, zkName string, additionalChecks func(Gomega, 
*zkApi.ZookeeperCluster), additionalOffset ...int) *zkApi.ZookeeperCluster {
+       found := &zkApi.ZookeeperCluster{}
+       EventuallyWithOffset(resolveOffset(additionalOffset), func(g Gomega) {
+               g.Expect(k8sClient.Get(ctx, resourceKey(parentResource, 
zkName), found)).To(Succeed(), "Expected ZookeeperCluster does not exist")
+               if additionalChecks != nil {
+                       additionalChecks(g, found)
+               }
+       }).Should(Succeed())
+
+       return found
+}
+
+func expectZookeeperClusterWithConsistentChecks(ctx context.Context, 
parentResource client.Object, zkName string, additionalChecks func(Gomega, 
*zkApi.ZookeeperCluster), additionalOffset ...int) *zkApi.ZookeeperCluster {
+       found := &zkApi.ZookeeperCluster{}
+       ConsistentlyWithOffset(resolveOffset(additionalOffset), func(g Gomega) {
+               g.Expect(k8sClient.Get(ctx, resourceKey(parentResource, 
zkName), found)).To(Succeed(), "Expected ZookeeperCluster does not exist")
+
+               if additionalChecks != nil {
+                       additionalChecks(g, found)
+               }
+       }).Should(Succeed())
+
+       return found
+}
+
 func expectSecret(ctx context.Context, parentResource client.Object, 
secretName string, additionalOffset ...int) *corev1.Secret {
        return expectSecretWithChecks(ctx, parentResource, secretName, nil, 
resolveOffset(additionalOffset))
 }
diff --git a/tests/e2e/solrcloud_basic_test.go 
b/tests/e2e/solrcloud_basic_test.go
new file mode 100644
index 0000000..673377d
--- /dev/null
+++ b/tests/e2e/solrcloud_basic_test.go
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package e2e
+
+import (
+       "context"
+       solrv1beta1 "github.com/apache/solr-operator/api/v1beta1"
+       . "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+       "k8s.io/utils/pointer"
+)
+
+var _ = FDescribe("E2E - SolrCloud - Basic", func() {
+       var (
+               solrCloud *solrv1beta1.SolrCloud
+
+               solrCollection1 = "e2e-1"
+
+               solrCollection2 = "e2e-2"
+       )
+
+       BeforeEach(func() {
+               solrCloud = generateBaseSolrCloud(1)
+       })
+
+       JustBeforeEach(func(ctx context.Context) {
+               By("creating the SolrCloud")
+               Expect(k8sClient.Create(ctx, solrCloud)).To(Succeed())
+
+               DeferCleanup(func(ctx context.Context) {
+                       cleanupTest(ctx, solrCloud)
+               })
+
+               By("Waiting for the SolrCloud to come up healthy")
+               solrCloud = 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")
+               })
+
+               By("creating a first Solr Collection")
+               createAndQueryCollection(solrCloud, solrCollection1, 1, 2)
+
+               By("creating a second Solr Collection")
+               createAndQueryCollection(solrCloud, solrCollection2, 2, 1)
+       })
+
+       FContext("Provided Zookeeper", func() {
+               BeforeEach(func() {
+                       solrCloud.Spec.ZookeeperRef = &solrv1beta1.ZookeeperRef{
+                               ProvidedZookeeper: &solrv1beta1.ZookeeperSpec{
+                                       Replicas:  pointer.Int32(1),
+                                       Ephemeral: &solrv1beta1.ZKEphemeral{},
+                               },
+                       }
+               })
+
+               // All testing will be done in the "JustBeforeEach" logic, no 
additional tests required here
+               FIt("Starts correctly", func(ctx context.Context) {})
+       })
+})
diff --git a/tests/e2e/solrcloud_rolling_upgrade_test.go 
b/tests/e2e/solrcloud_rolling_upgrade_test.go
index f261b44..c9256ff 100644
--- a/tests/e2e/solrcloud_rolling_upgrade_test.go
+++ b/tests/e2e/solrcloud_rolling_upgrade_test.go
@@ -22,12 +22,8 @@ import (
        solrv1beta1 "github.com/apache/solr-operator/api/v1beta1"
        . "github.com/onsi/ginkgo/v2"
        . "github.com/onsi/gomega"
-       corev1 "k8s.io/api/core/v1"
-       "k8s.io/apimachinery/pkg/api/resource"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/util/intstr"
        "sigs.k8s.io/controller-runtime/pkg/client"
-       "strings"
 )
 
 var _ = FDescribe("E2E - SolrCloud - Rolling Upgrades", func() {
@@ -40,43 +36,17 @@ var _ = FDescribe("E2E - SolrCloud - Rolling Upgrades", 
func() {
        )
 
        BeforeEach(func() {
-               solrCloud = &solrv1beta1.SolrCloud{
-                       ObjectMeta: metav1.ObjectMeta{
-                               Name:      "foo",
-                               Namespace: testNamespace(),
-                       },
-                       Spec: solrv1beta1.SolrCloudSpec{
-                               Replicas: &three,
-                               SolrImage: &solrv1beta1.ContainerImage{
-                                       Repository: strings.Split(solrImage, 
":")[0],
-                                       Tag:        
strings.Split(solrImage+":", ":")[1],
-                                       PullPolicy: corev1.PullIfNotPresent,
-                               },
-                               ZookeeperRef: &solrv1beta1.ZookeeperRef{
-                                       ProvidedZookeeper: 
&solrv1beta1.ZookeeperSpec{
-                                               Replicas:  &one,
-                                               Ephemeral: 
&solrv1beta1.ZKEphemeral{},
-                                       },
-                               },
-                               SolrJavaMem: "-Xms512m -Xmx512m",
-                               CustomSolrKubeOptions: 
solrv1beta1.CustomSolrKubeOptions{
-                                       PodOptions: &solrv1beta1.PodOptions{
-                                               Resources: 
corev1.ResourceRequirements{
-                                                       Requests: 
corev1.ResourceList{
-                                                               
corev1.ResourceMemory: resource.MustParse("600Mi"),
-                                                               
corev1.ResourceCPU:    resource.MustParse("1"),
-                                                       },
-                                               },
-                                       },
-                               },
-                       },
-               }
+               solrCloud = generateBaseSolrCloud(3)
        })
 
        JustBeforeEach(func(ctx context.Context) {
                By("creating the SolrCloud")
                Expect(k8sClient.Create(ctx, solrCloud)).To(Succeed())
 
+               DeferCleanup(func(ctx context.Context) {
+                       cleanupTest(ctx, solrCloud)
+               })
+
                By("Waiting for the SolrCloud to come up healthy")
                solrCloud = 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")
@@ -89,10 +59,6 @@ var _ = FDescribe("E2E - SolrCloud - Rolling Upgrades", 
func() {
                createAndQueryCollection(solrCloud, solrCollection2, 2, 1)
        })
 
-       AfterEach(func(ctx context.Context) {
-               cleanupTest(ctx, solrCloud)
-       })
-
        FContext("Managed Update - Ephemeral Data - Slow", func() {
                BeforeEach(func() {
                        one := intstr.FromInt(1)
diff --git a/tests/e2e/suite_test.go b/tests/e2e/suite_test.go
index d16c9e0..14eeb3d 100644
--- a/tests/e2e/suite_test.go
+++ b/tests/e2e/suite_test.go
@@ -25,9 +25,6 @@ import (
        "github.com/go-logr/logr"
        "github.com/onsi/ginkgo/v2/types"
        zkApi "github.com/pravega/zookeeper-operator/api/v1beta1"
-       "helm.sh/helm/v3/pkg/release"
-       corev1 "k8s.io/api/core/v1"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/kubernetes/scheme"
        "k8s.io/client-go/rest"
@@ -49,14 +46,18 @@ const (
        solrImageEnv     = "SOLR_IMAGE"
 
        backupDirHostPath = "/tmp/backup"
+
+       // Shared testing specs
+       timeout  = time.Second * 180
+       duration = time.Millisecond * 500
+       interval = time.Millisecond * 250
 )
 
 var (
-       solrOperatorRelease *release.Release
-       k8sClient           client.Client
-       rawK8sClient        *kubernetes.Clientset
-       k8sConfig           *rest.Config
-       logger              logr.Logger
+       k8sClient    client.Client
+       rawK8sClient *kubernetes.Clientset
+       k8sConfig    *rest.Config
+       logger       logr.Logger
 
        defaultOperatorImage = "apache/solr-operator:" + version.FullVersion()
        defaultSolrImage     = "solr:8.11"
@@ -73,20 +74,34 @@ func TestE2E(t *testing.T) {
 }
 
 var _ = SynchronizedBeforeSuite(func(ctx context.Context) {
+       // Define testing timeouts/durations and intervals.
+       SetDefaultEventuallyTimeout(timeout)
+       SetDefaultEventuallyPollingInterval(interval)
+
+       logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))
+       logf.SetLogger(logger)
+
        // Run this once before all tests, not per-test-process
        By("starting the test solr operator")
-       solrOperatorRelease = runSolrOperator(ctx)
+       solrOperatorRelease := runSolrOperator(ctx)
        Expect(solrOperatorRelease).ToNot(BeNil())
+
+       var err error
+       k8sConfig, err = config.GetConfig()
+       Expect(err).NotTo(HaveOccurred(), "Could not load in default kubernetes 
config")
+       Expect(zkApi.AddToScheme(scheme.Scheme)).To(Succeed())
+       k8sClient, err = client.New(k8sConfig, client.Options{Scheme: 
scheme.Scheme})
+       Expect(err).NotTo(HaveOccurred(), "Could not create controllerRuntime 
Kubernetes client")
+
+       // Set up a shared Zookeeper Cluster to be used for most SolrClouds
+       // This will significantly speed up tests
+       By("starting a shared zookeeper cluster")
+       runSharedZookeeperCluster(ctx)
 }, func(ctx context.Context) {
        // Run these in each parallel test process before the tests
        rand.Seed(GinkgoRandomSeed() + int64(GinkgoParallelProcess()))
 
        // Define testing timeouts/durations and intervals.
-       const (
-               timeout  = time.Second * 180
-               duration = time.Millisecond * 500
-               interval = time.Millisecond * 250
-       )
        SetDefaultConsistentlyDuration(duration)
        SetDefaultConsistentlyPollingInterval(interval)
        SetDefaultEventuallyTimeout(timeout)
@@ -109,30 +124,8 @@ var _ = SynchronizedBeforeSuite(func(ctx context.Context) {
        k8sClient, err = client.New(k8sConfig, client.Options{Scheme: 
scheme.Scheme})
        Expect(err).NotTo(HaveOccurred(), "Could not create controllerRuntime 
Kubernetes client")
 
-       // Delete the testing namespace if it already exists, then recreate it 
below
-       namespace := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: 
testNamespace()}}
-       err = k8sClient.Get(ctx, client.ObjectKey{Name: testNamespace()}, 
namespace)
-       if err == nil {
-               By("deleting the existing namespace for this parallel test 
process before recreating it")
-               deleteAndWait(ctx, namespace)
-       }
-
        By("creating a namespace for this parallel test process")
-       Expect(k8sClient.Create(ctx, &corev1.Namespace{ObjectMeta: 
metav1.ObjectMeta{Name: testNamespace()}})).
-               To(Succeed(), "Failed to create testing namespace %s", 
testNamespace())
-})
-
-var _ = SynchronizedAfterSuite(func(ctx context.Context) {
-       // Run these in each parallel test process after the tests
-       By("deleting the namespace for this parallel test process")
-       Expect(k8sClient.Delete(ctx, &corev1.Namespace{ObjectMeta: 
metav1.ObjectMeta{Name: testNamespace()}}, 
client.PropagationPolicy(metav1.DeletePropagationForeground))).
-               To(Or(Succeed(), MatchError(HaveSuffix("%q not found", 
testNamespace()))), "Failed to delete testing namespace %s", testNamespace())
-}, func() {
-       // Run this once after all tests, not per-test-process
-       if solrOperatorRelease != nil {
-               By("tearing down the test solr operator")
-               stopSolrOperator(solrOperatorRelease)
-       }
+       createOrRecreateNamespace(ctx, testNamespace())
 })
 
 type RetryCommand struct {
diff --git a/tests/e2e/test_utils_test.go b/tests/e2e/test_utils_test.go
index ee503a2..c3a262e 100644
--- a/tests/e2e/test_utils_test.go
+++ b/tests/e2e/test_utils_test.go
@@ -27,15 +27,20 @@ import (
        "github.com/apache/solr-operator/controllers/util/solr_api"
        . "github.com/onsi/ginkgo/v2"
        . "github.com/onsi/gomega"
+       zkApi "github.com/pravega/zookeeper-operator/api/v1beta1"
        "helm.sh/helm/v3/pkg/action"
        "helm.sh/helm/v3/pkg/chart/loader"
        "helm.sh/helm/v3/pkg/cli"
        "helm.sh/helm/v3/pkg/release"
        "helm.sh/helm/v3/pkg/storage/driver"
        corev1 "k8s.io/api/core/v1"
+       "k8s.io/apimachinery/pkg/api/resource"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/labels"
        "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/util/rand"
        "k8s.io/client-go/tools/remotecommand"
+       "k8s.io/utils/pointer"
        "os"
        "sigs.k8s.io/controller-runtime/pkg/client"
        "strings"
@@ -47,6 +52,10 @@ const (
 
        solrOperatorReleaseName      = "solr-operator"
        solrOperatorReleaseNamespace = "solr-operator"
+
+       sharedZookeeperName             = "shared"
+       sharedZookeeperNamespace        = "zk"
+       sharedZookeeperConnectionString = sharedZookeeperName + "-client." + 
sharedZookeeperNamespace + ":2181"
 )
 
 var (
@@ -66,9 +75,9 @@ func runSolrOperator(ctx context.Context) *release.Release {
        Expect(found).To(BeTrue(), "Invalid Operator image found in envVar 
OPERATOR_IMAGE: "+operatorImage)
        operatorValues := map[string]interface{}{
                "image": map[string]interface{}{
-                       "repostitory": operatorRepo,
-                       "tag":         operatorTag,
-                       "pullPolicy":  "Never",
+                       "repository": operatorRepo,
+                       "tag":        operatorTag,
+                       "pullPolicy": "Never",
                },
        }
 
@@ -99,6 +108,11 @@ func runSolrOperator(ctx context.Context) *release.Release {
        Expect(err).ToNot(HaveOccurred(), "Failed to install solr-operator via 
Helm chart")
        Expect(solrOperatorHelmRelease).ToNot(BeNil(), "Failed to install 
solr-operator via Helm chart")
 
+       DeferCleanup(func(ctx context.Context) {
+               By("tearing down the test solr operator")
+               stopSolrOperator(solrOperatorHelmRelease)
+       })
+
        return solrOperatorHelmRelease
 }
 
@@ -113,7 +127,46 @@ func stopSolrOperator(release *release.Release) {
        Expect(err).ToNot(HaveOccurred(), "Failed to uninstall solr-operator 
release: "+release.Name)
 }
 
+// Run a Zookeeper Cluster to be used for most of the SolrClouds across the 
e2e tests.
+// This will speed up the tests considerably, as each SolrCloud does not need 
to wait on Zookeeper to become available.
+func runSharedZookeeperCluster(ctx context.Context) *zkApi.ZookeeperCluster {
+       createOrRecreateNamespace(ctx, sharedZookeeperNamespace)
+
+       zookeeper := &zkApi.ZookeeperCluster{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      sharedZookeeperName,
+                       Namespace: sharedZookeeperNamespace,
+               },
+               Spec: zkApi.ZookeeperClusterSpec{
+                       Replicas:    one,
+                       StorageType: "Ephemeral",
+               },
+       }
+
+       By("creating the shared ZK cluster")
+       Expect(k8sClient.Create(ctx, zookeeper)).To(Succeed(), "Failed to 
create shared Zookeeper Cluster")
+
+       By("Waiting for the Zookeeper to come up healthy")
+       zookeeper = expectZookeeperClusterWithChecks(ctx, zookeeper, 
zookeeper.Name, func(g Gomega, found *zkApi.ZookeeperCluster) {
+               
g.Expect(found.Status.ReadyReplicas).To(Equal(found.Spec.Replicas), "The 
ZookeeperCluster should have all nodes come up healthy")
+       })
+
+       DeferCleanup(func(ctx context.Context) {
+               By("tearing down the shared Zookeeper Cluster")
+               stopSharedZookeeperCluster(ctx, zookeeper)
+       })
+
+       return zookeeper
+}
+
 // Run Solr Operator for e2e testing of resources
+func stopSharedZookeeperCluster(ctx context.Context, sharedZk 
*zkApi.ZookeeperCluster) {
+       err := k8sClient.Get(ctx, client.ObjectKey{Namespace: 
sharedZk.Namespace, Name: sharedZk.Name}, sharedZk)
+       if err == nil {
+               Expect(k8sClient.Delete(ctx, sharedZk)).To(Succeed(), "Failed 
to delete shared Zookeeper Cluster")
+       }
+}
+
 func getEnvWithDefault(envVar string, defaultValue string) string {
        value := os.Getenv(envVar)
        if value == "" {
@@ -122,13 +175,42 @@ func getEnvWithDefault(envVar string, defaultValue 
string) string {
        return value
 }
 
-func createAndQueryCollection(solrCloud *solrv1beta1.SolrCloud, collection 
string, shards int, replicasPerShard int) {
-       createAndQueryCollectionWithGomega(solrCloud, collection, shards, 
replicasPerShard, Default)
+// Delete the given namespace if it already exists, then create/recreate it
+func createOrRecreateNamespace(ctx context.Context, namespaceName string) {
+       namespace := &corev1.Namespace{}
+       err := k8sClient.Get(ctx, client.ObjectKey{Name: namespaceName}, 
namespace)
+       if err == nil {
+               By("deleting the existing namespace " + namespaceName)
+               deleteAndWait(ctx, namespace)
+       }
+
+       namespace = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: 
namespaceName}}
+       Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "Failed to 
create namespace %s", namespaceName)
+
+       DeferCleanup(func(ctx context.Context) {
+               By("tearing down the testingNamespace " + namespaceName)
+               Expect(k8sClient.Delete(ctx, &corev1.Namespace{ObjectMeta: 
metav1.ObjectMeta{Name: namespaceName}}, 
client.PropagationPolicy(metav1.DeletePropagationForeground))).
+                       To(Or(Succeed(), MatchError(HaveSuffix("%q not found", 
namespaceName))), "Failed to delete testing namespace %s", namespaceName)
+       })
 }
 
-func createAndQueryCollectionWithGomega(solrCloud *solrv1beta1.SolrCloud, 
collection string, shards int, replicasPerShard int, g Gomega) {
+func createAndQueryCollection(solrCloud *solrv1beta1.SolrCloud, collection 
string, shards int, replicasPerShard int, nodes ...int) {
+       createAndQueryCollectionWithGomega(solrCloud, collection, shards, 
replicasPerShard, Default, nodes...)
+}
+
+func createAndQueryCollectionWithGomega(solrCloud *solrv1beta1.SolrCloud, 
collection string, shards int, replicasPerShard int, g Gomega, nodes ...int) {
        pod := solrCloud.GetAllSolrPodNames()[0]
        asyncId := fmt.Sprintf("create-collection-%s-%d-%d", collection, 
shards, replicasPerShard)
+
+       var nodeSet []string
+       for _, node := range nodes {
+               nodeSet = append(nodeSet, util.SolrNodeName(solrCloud, 
solrCloud.GetSolrPodName(node)))
+       }
+       createNodeSet := ""
+       if len(nodeSet) > 0 {
+               createNodeSet = "&createNodeSet=" + strings.Join(nodeSet, ",")
+       }
+
        response, err := runExecForContainer(
                util.SolrNodeContainer,
                pod,
@@ -136,11 +218,12 @@ func createAndQueryCollectionWithGomega(solrCloud 
*solrv1beta1.SolrCloud, collec
                []string{
                        "curl",
                        fmt.Sprintf(
-                               
"http://localhost:%d/solr/admin/collections?action=CREATE&name=%s&replicationFactor=%d&numShards=%d&async=%s";,
+                               
"http://localhost:%d/solr/admin/collections?action=CREATE&name=%s&replicationFactor=%d&numShards=%d%s&async=%s";,
                                solrCloud.Spec.SolrAddressability.PodPort,
                                collection,
                                replicasPerShard,
                                shards,
+                               createNodeSet,
                                asyncId),
                },
        )
@@ -343,3 +426,40 @@ func runExecForContainer(container string, podName string, 
namespace string, com
 
        return stdout.String(), err
 }
+
+func generateBaseSolrCloud(replicas int) *solrv1beta1.SolrCloud {
+       return &solrv1beta1.SolrCloud{
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      "foo",
+                       Namespace: testNamespace(),
+               },
+               Spec: solrv1beta1.SolrCloudSpec{
+                       Replicas: pointer.Int32(int32(replicas)),
+                       // Set the image to reflect the inputs given via 
EnvVars.
+                       SolrImage: &solrv1beta1.ContainerImage{
+                               Repository: strings.Split(solrImage, ":")[0],
+                               Tag:        strings.Split(solrImage+":", 
":")[1],
+                               PullPolicy: corev1.PullIfNotPresent,
+                       },
+                       // Use the shared Zookeeper by default, with a unique 
chRoot for this test
+                       ZookeeperRef: &solrv1beta1.ZookeeperRef{
+                               ConnectionInfo: 
&solrv1beta1.ZookeeperConnectionInfo{
+                                       InternalConnectionString: 
sharedZookeeperConnectionString,
+                                       ChRoot:                   "/" + 
rand.String(5),
+                               },
+                       },
+                       // This seems to be the lowest memory & CPU that allow 
the tests to pass
+                       SolrJavaMem: "-Xms512m -Xmx512m",
+                       CustomSolrKubeOptions: 
solrv1beta1.CustomSolrKubeOptions{
+                               PodOptions: &solrv1beta1.PodOptions{
+                                       Resources: corev1.ResourceRequirements{
+                                               Requests: corev1.ResourceList{
+                                                       corev1.ResourceMemory: 
resource.MustParse("600Mi"),
+                                                       corev1.ResourceCPU:    
resource.MustParse("1"),
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+}

Reply via email to