From a835902f51010ff911ea8ad91e8435bdbd16ecf5 Mon Sep 17 00:00:00 2001 From: ddalvi Date: Wed, 6 Mar 2024 13:23:31 -0500 Subject: [PATCH] Refactor integration test suite to use testify --- Makefile | 2 +- tests/README.md | 8 +-- tests/dspa_v2_test.go | 54 ++++++++-------- tests/experiments_test.go | 22 ++++--- tests/pipeline_test.go | 30 ++++----- tests/suite_test.go | 128 ++++++++++++++++++++------------------ tests/util/resources.go | 89 +++++++++++++++----------- tests/util/rest.go | 26 +++++--- 8 files changed, 193 insertions(+), 166 deletions(-) diff --git a/Makefile b/Makefile index a404df2af..dfdeced42 100644 --- a/Makefile +++ b/Makefile @@ -128,7 +128,7 @@ functest: manifests generate fmt vet envtest ## Run tests. .PHONY: integrationtest integrationtest: ## Run integration tests cd tests && \ - go run github.com/onsi/ginkgo/v2/ginkgo --tags=test_integration -- -kubeconfig=${KUBECONFIGPATH} -k8sApiServerHost=${K8SAPISERVERHOST} -DSPANamespace=${DSPANAMESPACE} -DSPAPath=${DSPAPATH} -ginkgo.v + go test ./... --tags=test_integration -v -kubeconfig=${KUBECONFIGPATH} -k8sApiServerHost=${K8SAPISERVERHOST} -DSPANamespace=${DSPANAMESPACE} -DSPAPath=${DSPAPATH} ##@ Build diff --git a/tests/README.md b/tests/README.md index 9e11a324a..ef7c2ae32 100644 --- a/tests/README.md +++ b/tests/README.md @@ -46,12 +46,12 @@ For the impatient developer, you can use the following flag to skip DSPA install changes to a live environment and run the tests against it: ```bash -go run github.com/onsi/ginkgo/v2/ginkgo --tags=test_integration -- \ +go test ./... --tags=test_integration -v \ -kubeconfig=${KUBECONFIG_PATH} \ -k8sApiServerHost=${TARGET_CLUSTER} \ - -DSPANamespace=${TARGET_NAMESPACE} -DSPAPath=resources/dspa-lite.yaml \ - -ginkgo.v - -skipDeploy=true + -DSPANamespace=${TARGET_NAMESPACE} \ + -DSPAPath=resources/dspa-lite.yaml + -skipDeploy=true \ -skipCleanup=true ``` diff --git a/tests/dspa_v2_test.go b/tests/dspa_v2_test.go index 058cbf0b8..bb2acf2ca 100644 --- a/tests/dspa_v2_test.go +++ b/tests/dspa_v2_test.go @@ -20,42 +20,40 @@ package integration import ( "fmt" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - systemsTesttUtil "github.com/opendatahub-io/data-science-pipelines-operator/tests/util" + "testing" + + testUtil "github.com/opendatahub-io/data-science-pipelines-operator/tests/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) -var _ = Describe("A successfully deployed DSPA", func() { - +func (suite *IntegrationTestSuite) TestDSPADeployment() { podCount := 8 - - Context("with default MariaDB and Minio", func() { - It(fmt.Sprintf("should have %d pods", podCount), func() { + suite.T().Run("with default MariaDB and Minio", func(t *testing.T) { + t.Run(fmt.Sprintf("should have %d pods", podCount), func(t *testing.T) { podList := &corev1.PodList{} listOpts := []client.ListOption{ - client.InNamespace(DSPANamespace), + client.InNamespace(suite.DSPANamespace), } - err := clientmgr.k8sClient.List(ctx, podList, listOpts...) - Expect(err).ToNot(HaveOccurred()) - Expect(len(podList.Items)).Should(Equal(podCount)) + err := suite.Clientmgr.k8sClient.List(suite.Ctx, podList, listOpts...) + require.NoError(t, err) + assert.Equal(t, podCount, len(podList.Items)) }) - It(fmt.Sprintf("should have a ready %s deployment", "DSP API Server"), func() { - systemsTesttUtil.TestForSuccessfulDeployment(ctx, DSPANamespace, fmt.Sprintf("ds-pipeline-%s", DSPA.Name), clientmgr.k8sClient) - }) - It(fmt.Sprintf("should have a ready %s deployment", "Persistence Agent"), func() { - systemsTesttUtil.TestForSuccessfulDeployment(ctx, DSPANamespace, fmt.Sprintf("ds-pipeline-persistenceagent-%s", DSPA.Name), clientmgr.k8sClient) - }) - It(fmt.Sprintf("should have a ready %s deployment", "Scheduled Workflow"), func() { - systemsTesttUtil.TestForSuccessfulDeployment(ctx, DSPANamespace, fmt.Sprintf("ds-pipeline-scheduledworkflow-%s", DSPA.Name), clientmgr.k8sClient) - }) - It(fmt.Sprintf("should have a ready %s deployment", "MariaDB"), func() { - systemsTesttUtil.TestForSuccessfulDeployment(ctx, DSPANamespace, fmt.Sprintf("mariadb-%s", DSPA.Name), clientmgr.k8sClient) - }) - It(fmt.Sprintf("should have a ready %s deployment", "Minio"), func() { - systemsTesttUtil.TestForSuccessfulDeployment(ctx, DSPANamespace, fmt.Sprintf("minio-%s", DSPA.Name), clientmgr.k8sClient) - }) + deployments := []string{ + fmt.Sprintf("ds-pipeline-%s", suite.DSPA.Name), + fmt.Sprintf("ds-pipeline-persistenceagent-%s", suite.DSPA.Name), + fmt.Sprintf("ds-pipeline-scheduledworkflow-%s", suite.DSPA.Name), + fmt.Sprintf("mariadb-%s", suite.DSPA.Name), + fmt.Sprintf("minio-%s", suite.DSPA.Name), + } + + for _, deployment := range deployments { + t.Run(fmt.Sprintf("should have a ready %s deployment", deployment), func(t *testing.T) { + testUtil.TestForSuccessfulDeployment(t, suite.Ctx, suite.DSPANamespace, deployment, suite.Clientmgr.k8sClient) + }) + } }) -}) +} diff --git a/tests/experiments_test.go b/tests/experiments_test.go index 1750c6786..7c4b4726c 100644 --- a/tests/experiments_test.go +++ b/tests/experiments_test.go @@ -20,21 +20,23 @@ package integration import ( "fmt" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" "io/ioutil" "net/http" + "testing" + + "github.com/stretchr/testify/require" ) -var _ = Describe("A successfully deployed DSPA", func() { - It("Should successfully fetch experiments.", func() { +func (suite *IntegrationTestSuite) TestFetchExperiments() { + suite.T().Run("Should successfully fetch experiments", func(t *testing.T) { response, err := http.Get(fmt.Sprintf("%s/apis/v2beta1/experiments", APIServerURL)) - Expect(err).ToNot(HaveOccurred()) - responseData, err := ioutil.ReadAll(response.Body) - loggr.Info(string(responseData)) + require.NoError(t, err, "Error fetching experiments") - Expect(err).ToNot(HaveOccurred()) - Expect(response.StatusCode).To(Equal(200)) + responseData, err := ioutil.ReadAll(response.Body) + defer response.Body.Close() + require.NoError(t, err, "Error reading response body") + suite.Assert().Equal(200, response.StatusCode, "Expected HTTP status code 200 for fetching experiments") + loggr.Info(string(responseData)) }) -}) +} diff --git a/tests/pipeline_test.go b/tests/pipeline_test.go index 30c50cf3d..4ffc666a4 100644 --- a/tests/pipeline_test.go +++ b/tests/pipeline_test.go @@ -20,37 +20,39 @@ package integration import ( "fmt" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - systemsTesttUtil "github.com/opendatahub-io/data-science-pipelines-operator/tests/util" "io/ioutil" "net/http" + "testing" + + TestUtil "github.com/opendatahub-io/data-science-pipelines-operator/tests/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -var _ = Describe("A successfully deployed API Server", func() { - It("Should successfully fetch pipelines.", func() { +func (suite *IntegrationTestSuite) TestAPIServerDeployment() { + suite.T().Run("Should successfully fetch pipelines", func(t *testing.T) { response, err := http.Get(fmt.Sprintf("%s/apis/v2beta1/pipelines", APIServerURL)) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err) responseData, err := ioutil.ReadAll(response.Body) - Expect(err).ToNot(HaveOccurred()) - Expect(response.StatusCode).To(Equal(200)) + require.NoError(t, err) + assert.Equal(t, 200, response.StatusCode) loggr.Info(string(responseData)) }) - It("Should successfully upload a pipeline.", func() { + suite.T().Run("Should successfully upload a pipeline", func(t *testing.T) { postUrl := fmt.Sprintf("%s/apis/v2beta1/pipelines/upload", APIServerURL) vals := map[string]string{ "uploadfile": "@resources/test-pipeline-run.yaml", } - body, contentType := systemsTesttUtil.FormFromFile(vals) + body, contentType := TestUtil.FormFromFile(t, vals) response, err := http.Post(postUrl, contentType, body) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err) responseData, err := ioutil.ReadAll(response.Body) responseString := string(responseData) loggr.Info(responseString) - Expect(err).ToNot(HaveOccurred()) - Expect(response.StatusCode).To(Equal(200)) + require.NoError(t, err) + assert.Equal(t, 200, response.StatusCode) }) -}) +} diff --git a/tests/suite_test.go b/tests/suite_test.go index c83f80de5..512fac361 100644 --- a/tests/suite_test.go +++ b/tests/suite_test.go @@ -22,14 +22,18 @@ import ( "context" "flag" "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/anthhub/forwarder" "github.com/go-logr/logr" mfc "github.com/manifestival/controller-runtime-client" mf "github.com/manifestival/manifestival" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" dspav1alpha1 "github.com/opendatahub-io/data-science-pipelines-operator/api/v1alpha1" - systemsTesttUtil "github.com/opendatahub-io/data-science-pipelines-operator/tests/util" + testUtil "github.com/opendatahub-io/data-science-pipelines-operator/tests/util" + "github.com/stretchr/testify/suite" "go.uber.org/zap/zapcore" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes/scheme" @@ -38,12 +42,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "testing" - "time" -) - -const ( - APIServerPort = 8888 ) var ( @@ -72,6 +70,7 @@ var ( ) const ( + APIServerPort = 8888 DefaultKubeConfigPath = "~/.kube/config" Defaultk8sApiServerHost = "localhost:6443" DefaultDSPANamespace = "default" @@ -90,19 +89,27 @@ type ClientManager struct { mfopts mf.Option } -// TestAPIs - This is the entry point for Ginkgo - -// the go test runner will run this function when you run go test or ginkgo. -// Under the hood, Ginkgo is simply calling go test. -// You can run go test instead of the ginkgo CLI, But Ginkgo has several capabilities that can only be accessed via ginkgo. -// It is best practice to embrace the ginkgo CLI and treat it as a first-class member of the testing toolchain. -func TestAPIs(t *testing.T) { - // Single line of glue code connecting Ginkgo to Gomega - // Inform our matcher library (Gomega) which function to call (Ginkgo's Fail) in the event a failure is detected. - RegisterFailHandler(Fail) - - // Inform Ginkgo to start the test suite, passing it the *testing.T instance and a description of the suite. - // Only call RunSpecs once and let Ginkgo worry about calling *testing.T for us. - RunSpecs(t, "Controller Suite") +type IntegrationTestSuite struct { + suite.Suite + Clientmgr ClientManager + Ctx context.Context + DSPANamespace string + DSPA *dspav1alpha1.DataSciencePipelinesApplication +} + +type testLogWriter struct { + t *testing.T +} + +func (w *testLogWriter) Write(p []byte) (n int, err error) { + w.t.Log(string(p)) + return len(p), nil +} + +// newTestLogWriter creates a new instance of testLogWriter +// that adapts *testing.T to an io.Writer. +func newTestLogWriter(t *testing.T) *testLogWriter { + return &testLogWriter{t: t} } // Register flags in an init function. This ensures they are registered _before_ `go test` calls flag.Parse() @@ -118,7 +125,6 @@ func init() { PollInterval *= time.Second flag.DurationVar(&DeleteTimeout, "DeleteTimeout", DefaultDeleteTimeout, "Seconds to wait for deployment deletions. Consider increasing this on resource starved environments.") DeleteTimeout *= time.Second - flag.IntVar(&PortforwardLocalPort, "PortforwardLocalPort", DefaultPortforwardLocalPort, "Local port to use for port forwarding dspa server.") flag.BoolVar(&skipDeploy, "skipDeploy", DefaultSkipDeploy, "Skip DSPA deployment. Use this if you have already "+ @@ -126,81 +132,79 @@ func init() { flag.BoolVar(&skipCleanup, "skipCleanup", DefaultSkipCleanup, "Skip DSPA cleanup.") } -var _ = BeforeSuite(func() { - ctx, cancel = context.WithCancel(context.TODO()) +func (suite *IntegrationTestSuite) SetupSuite() { + loggr = logf.Log + ctx, cancel = context.WithCancel(context.Background()) + suite.Ctx = ctx // Initialize logger opts := zap.Options{ Development: true, TimeEncoder: zapcore.TimeEncoderOfLayout(time.RFC3339), } - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseFlagOptions(&opts))) + logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(newTestLogWriter(suite.T())), zap.UseFlagOptions(&opts))) - loggr = logf.Log var err error - // Register API objects utilruntime.Must(dspav1alpha1.AddToScheme(scheme.Scheme)) - clientmgr = ClientManager{} - // Set up client auth configs cfg, err = clientcmd.BuildConfigFromFlags(k8sApiServerHost, kubeconfig) - Expect(err).ToNot(HaveOccurred()) + suite.Require().NoError(err) - // Initialize Kubernetes client clientmgr.k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(clientmgr.k8sClient).NotTo(BeNil()) + suite.Require().NoError(err) + suite.Require().NotNil(clientmgr.k8sClient) clientmgr.mfsClient = mfc.NewClient(clientmgr.k8sClient) clientmgr.mfopts = mf.UseClient(clientmgr.mfsClient) + suite.Clientmgr = clientmgr - // Get DSPA structured - DSPA = systemsTesttUtil.GetDSPAFromPath(clientmgr.mfopts, DSPAPath) + DSPA = testUtil.GetDSPAFromPath(suite.T(), clientmgr.mfopts, DSPAPath) + + suite.DSPANamespace = DSPANamespace + suite.DSPA = DSPA if !skipDeploy { loggr.Info("Deploying DSPA...") - systemsTesttUtil.DeployDSPA(ctx, clientmgr.k8sClient, DSPA, DSPANamespace, DeployTimeout, PollInterval) + err = testUtil.DeployDSPA(suite.T(), ctx, clientmgr.k8sClient, DSPA, DSPANamespace, DeployTimeout, PollInterval) + assert.NoError(suite.T(), err) loggr.Info("Waiting for DSPA pods to ready...") - systemsTesttUtil.WaitForDSPAReady(ctx, clientmgr.k8sClient, DSPA.Name, DSPANamespace, DeployTimeout, PollInterval) - loggr.Info("DSPA Deployed.") } - // Forward ApiServer Service + err = testUtil.WaitForDSPAReady(suite.T(), ctx, clientmgr.k8sClient, DSPA.Name, DSPANamespace, DeployTimeout, PollInterval) + assert.NoError(suite.T(), err) + loggr.Info("DSPA Deployed.") + loggr.Info("Setting up Portforwarding service.") options := []*forwarder.Option{ { - // the local port for forwarding - LocalPort: PortforwardLocalPort, - // the k8s pod port - RemotePort: APIServerPort, - // the forwarding service name + LocalPort: PortforwardLocalPort, + RemotePort: APIServerPort, ServiceName: fmt.Sprintf("ds-pipeline-%s", DSPA.Name), - // namespace default is "default" - Namespace: DSPANamespace, + Namespace: DSPANamespace, }, } - // Create a forwarder, and provide a path to kubeconfig - forwarderResult, err = forwarder.WithForwarders(context.Background(), options, kubeconfig) - Expect(err).NotTo(HaveOccurred()) - // wait forwarding ready + + forwarderResult, err = forwarder.WithForwarders(ctx, options, kubeconfig) + suite.Require().NoError(err) _, err = forwarderResult.Ready() - Expect(err).NotTo(HaveOccurred()) - loggr.Info("Portforwarding service Successfully set up.") + suite.Require().NoError(err) APIServerURL = fmt.Sprintf("http://127.0.0.1:%d", PortforwardLocalPort) + loggr.Info("Portforwarding service Successfully set up.") +} - loggr.Info("Starting Test Suite.") -}) - -var _ = BeforeEach(func() { -}) - -var _ = AfterSuite(func() { +func (suite *IntegrationTestSuite) TearDownSuite() { if !skipCleanup { - systemsTesttUtil.DeleteDSPA(ctx, clientmgr.k8sClient, DSPA.Name, DSPANamespace, DeployTimeout, PollInterval) + err := testUtil.DeleteDSPA(suite.T(), ctx, clientmgr.k8sClient, DSPA.Name, DSPANamespace, DeployTimeout, PollInterval) + assert.NoError(suite.T(), err) } if forwarderResult != nil { forwarderResult.Close() } -}) + cancel() +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} diff --git a/tests/util/resources.go b/tests/util/resources.go index 4116879e0..0620494be 100644 --- a/tests/util/resources.go +++ b/tests/util/resources.go @@ -1,12 +1,9 @@ /* Copyright 2023. - Licensed 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. @@ -14,61 +11,68 @@ See the License for the specific language governing permissions and limitations under the License. */ -package systemsTesttUtil +package testUtil import ( "context" "fmt" + "testing" + "time" + mf "github.com/manifestival/manifestival" - . "github.com/onsi/gomega" "github.com/opendatahub-io/data-science-pipelines-operator/api/v1alpha1" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" - "time" ) // DeployDSPA will deploy resource found in path by requesting -func DeployDSPA(ctx context.Context, client client.Client, deployDSPA *v1alpha1.DataSciencePipelinesApplication, dspaNS string, timeout, interval time.Duration) { +func DeployDSPA(t *testing.T, ctx context.Context, client client.Client, deployDSPA *v1alpha1.DataSciencePipelinesApplication, dspaNS string, timeout, interval time.Duration) error { deployDSPA.ObjectMeta.Namespace = dspaNS err := client.Create(ctx, deployDSPA) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err) nsn := types.NamespacedName{ Name: deployDSPA.ObjectMeta.Name, Namespace: dspaNS, } fetchedDspa := &v1alpha1.DataSciencePipelinesApplication{} - Eventually(func() error { + return waitFor(ctx, timeout, interval, func() (bool, error) { err := client.Get(ctx, nsn, fetchedDspa) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) + if err != nil { + return false, err + } + return true, nil + }) } // WaitForDSPAReady will assert for DSPA CR Ready Status -func WaitForDSPAReady(ctx context.Context, client client.Client, dspaName, dspaNS string, timeout, interval time.Duration) { +func WaitForDSPAReady(t *testing.T, ctx context.Context, client client.Client, dspaName, dspaNS string, timeout, interval time.Duration) error { nsn := types.NamespacedName{ Name: dspaName, Namespace: dspaNS, } dspa := &v1alpha1.DataSciencePipelinesApplication{} - Eventually(func() metav1.ConditionStatus { + return waitFor(ctx, timeout, interval, func() (bool, error) { err := client.Get(ctx, nsn, dspa) - Expect(err).ToNot(HaveOccurred()) + if err != nil { + return false, err + } for _, condition := range dspa.Status.Conditions { - if condition.Type == "Ready" { - return condition.Status + if condition.Type == "Ready" && condition.Status == metav1.ConditionTrue { + return true, nil } } - return metav1.ConditionFalse - }, timeout, interval).Should(Equal(metav1.ConditionTrue)) + return false, nil + }) } // DeleteDSPA will delete DSPA found in path by requesting -func DeleteDSPA(ctx context.Context, client client.Client, dspaName, dspaNS string, timeout, interval time.Duration) { +func DeleteDSPA(t *testing.T, ctx context.Context, client client.Client, dspaName, dspaNS string, timeout, interval time.Duration) error { nsn := types.NamespacedName{ Name: dspaName, Namespace: dspaNS, @@ -80,45 +84,56 @@ func DeleteDSPA(ctx context.Context, client client.Client, dspaName, dspaNS stri }, } err := client.Delete(ctx, dspa) - Expect(err).ToNot(HaveOccurred()) - Eventually(func() error { + require.NoError(t, err) + return waitFor(ctx, timeout, interval, func() (bool, error) { err := client.Get(ctx, nsn, dspa) - if err != nil { - if apierrs.IsNotFound(err) { - return nil - } - return err + if apierrs.IsNotFound(err) { + return true, nil } - return fmt.Errorf("resource still exists on cluster") - - }, timeout, interval).ShouldNot(HaveOccurred()) - + return false, err + }) } -func TestForSuccessfulDeployment(ctx context.Context, namespace, deploymentName string, client client.Client) { +func TestForSuccessfulDeployment(t *testing.T, ctx context.Context, namespace, deploymentName string, client client.Client) { deployment := &appsv1.Deployment{} nsn := types.NamespacedName{ Name: deploymentName, Namespace: namespace, } err := client.Get(ctx, nsn, deployment) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err) deploymentAvailable := false for _, condition := range deployment.Status.Conditions { if condition.Reason == "MinimumReplicasAvailable" && condition.Type == appsv1.DeploymentAvailable { deploymentAvailable = true + break } } - Expect(deploymentAvailable).To(BeTrue()) - + require.True(t, deploymentAvailable) } -func GetDSPAFromPath(opts mf.Option, path string) *v1alpha1.DataSciencePipelinesApplication { +func GetDSPAFromPath(t *testing.T, opts mf.Option, path string) *v1alpha1.DataSciencePipelinesApplication { dspa := &v1alpha1.DataSciencePipelinesApplication{} manifest, err := mf.NewManifest(path, opts) - Expect(err).NotTo(HaveOccurred()) + require.NoError(t, err) expected := &manifest.Resources()[0] err = scheme.Scheme.Convert(expected, dspa, nil) - Expect(err).NotTo(HaveOccurred()) + require.NoError(t, err) return dspa } + +// waitFor is a helper function +func waitFor(ctx context.Context, timeout, interval time.Duration, conditionFunc func() (bool, error)) error { + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + done, err := conditionFunc() + if done { + return nil + } + if err != nil { + return err + } + time.Sleep(interval) + } + return fmt.Errorf("timed out waiting for condition") +} diff --git a/tests/util/rest.go b/tests/util/rest.go index 9ae7a6eaa..0da3e8472 100644 --- a/tests/util/rest.go +++ b/tests/util/rest.go @@ -1,12 +1,9 @@ /* Copyright 2023. - Licensed 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. @@ -14,35 +11,44 @@ See the License for the specific language governing permissions and limitations under the License. */ -package systemsTesttUtil +package testUtil import ( "bytes" - . "github.com/onsi/gomega" "io" "mime/multipart" "os" "strings" + "testing" + + "github.com/stretchr/testify/require" ) -func FormFromFile(form map[string]string) (*bytes.Buffer, string) { +// FormFromFile creates a multipart form data from the provided form map where the values are paths to files. +// It returns a buffer containing the encoded form data and the content type of the form. +// Requires passing the testing.T object for error handling with Testify. +func FormFromFile(t *testing.T, form map[string]string) (*bytes.Buffer, string) { body := new(bytes.Buffer) mp := multipart.NewWriter(body) defer mp.Close() + for key, val := range form { if strings.HasPrefix(val, "@") { val = val[1:] file, err := os.Open(val) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err, "Opening file failed") defer file.Close() + part, err := mp.CreateFormFile(key, val) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err, "Creating form file failed") + _, err = io.Copy(part, file) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err, "Copying file content failed") } else { err := mp.WriteField(key, val) - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err, "Writing form field failed") } } + return body, mp.FormDataContentType() }