func ExpectRequestToCreateHyperParameterTuningJob(req interface{}, tuningJobName string) {
	Expect(req).To(BeAssignableToTypeOf((*sagemaker.CreateHyperParameterTuningJobInput)(nil)))
	createdRequest := req.(*sagemaker.CreateHyperParameterTuningJobInput)
	Expect(*createdRequest.HyperParameterTuningJobName).To(Equal(tuningJobName))
}
Helper function to verify that there was an attempt to create a HyperParameterTuningJob with a given name.
package hyperparametertuningjob
import (
	"context"
	"errors"
	. "container/list"
	"github.com/google/uuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	commonv1 "github.com/aws/amazon-sagemaker-operator-for-k8s/api/v1/common"
	hpojobv1 "github.com/aws/amazon-sagemaker-operator-for-k8s/api/v1/hyperparametertuningjob"
	"github.com/aws/amazon-sagemaker-operator-for-k8s/controllers"
	. "github.com/aws/amazon-sagemaker-operator-for-k8s/controllers/controllertest"
	"github.com/aws/amazon-sagemaker-operator-for-k8s/controllers/sdkutil/clientwrapper"
	"github.com/go-logr/logr"
	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sagemaker"
	"github.com/aws/aws-sdk-go/service/sagemaker/sagemakeriface"
	apierrs "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
)
var _ = Describe("Reconciling a HyperParameterTuningJob while failing to get the Kubernetes job", func() {
	var (
		sageMakerClient sagemakeriface.SageMakerAPI
		reconciler *Reconciler
		reconcileResult ctrl.Result
		reconcileError error
		kubernetesClient k8sclient.Client
	)
	BeforeEach(func() {
		sageMakerClient = NewMockSageMakerClientBuilder(GinkgoT()).Build()
		kubernetesClient = k8sClient
	})
	JustBeforeEach(func() {
		reconciler = createReconciler(kubernetesClient, sageMakerClient, "1s", mockTrackingHPOTrainingJobSpawner{})
		request := CreateReconciliationRequest("non-existent-name", "namespace")
		reconcileResult, reconcileError = reconciler.Reconcile(request)
	})
	Context("No error with the K8s client", func() {
		It("should not requeue", func() {
			ExpectNoRequeue(reconcileResult, reconcileError)
		})
	})
	Context("An error occurred with the K8s client", func() {
		BeforeEach(func() {
			kubernetesClient = FailToGetK8sClient{}
		})
		It("should requeue immediately", func() {
			ExpectRequeueImmediately(reconcileResult, reconcileError)
		})
	})
})
var _ = Describe("Reconciling a HyperParameterTuningJob that exists", func() {
	var (
		receivedRequests List
		mockSageMakerClientBuilder *MockSageMakerClientBuilder
		jobSpawner *mockTrackingHPOTrainingJobSpawner
		expectedRequestCount int
		tuningJob *hpojobv1.HyperparameterTuningJob
		bestTrainingJob *sagemaker.HyperParameterTrainingJobSummary
		statusCounters *sagemaker.TrainingJobStatusCounters
		kubernetesClient k8sclient.Client
		pollDuration string
		shouldHaveDeletionTimestamp bool
		shouldHaveFinalizer bool
		reconcileResult ctrl.Result
		reconcileError error
	)
	BeforeEach(func() {
		pollDuration = "1s"
		shouldHaveDeletionTimestamp = false
		shouldHaveFinalizer = false
		kubernetesClient = k8sClient
		receivedRequests = List{}
		mockSageMakerClientBuilder = NewMockSageMakerClientBuilder(GinkgoT()).WithRequestList(&receivedRequests)
		bestTrainingJob = &sagemaker.HyperParameterTrainingJobSummary{
			TrainingJobName: ToStringPtr("best-training-job"),
		}
		statusCounters = &sagemaker.TrainingJobStatusCounters{
			Completed:         ToInt64Ptr(1),
			InProgress:        ToInt64Ptr(2),
			NonRetryableError: ToInt64Ptr(3),
			RetryableError:    ToInt64Ptr(4),
			Stopped:           ToInt64Ptr(5),
		}
		jobSpawner = &mockTrackingHPOTrainingJobSpawner{
			spawnMissingTrainingJobsCalls:  &List{},
			deleteSpawnedTrainingJobsCalls: &List{},
		}
		tuningJob = createHyperParameterTuningJobWithGeneratedNames()
	})
	JustBeforeEach(func() {
		sageMakerClient := mockSageMakerClientBuilder.Build()
		expectedRequestCount = mockSageMakerClientBuilder.GetAddedResponsesLen()
		controller := createReconciler(kubernetesClient, sageMakerClient, pollDuration, jobSpawner)
		err := k8sClient.Create(context.Background(), tuningJob)
		Expect(err).ToNot(HaveOccurred())
		if shouldHaveFinalizer {
			AddFinalizer(tuningJob)
		}
		if shouldHaveDeletionTimestamp {
			SetDeletionTimestamp(tuningJob)
		}
		request := CreateReconciliationRequest(tuningJob.ObjectMeta.GetName(), tuningJob.ObjectMeta.GetNamespace())
		reconcileResult, reconcileError = controller.Reconcile(request)
	})
	AfterEach(func() {
		Expect(receivedRequests.Len()).To(Equal(expectedRequestCount), "Expect that all SageMaker responses were consumed")
	})
	Context("DescribeHyperParameterTuningJob fails", func() {
		var failureMessage string
		BeforeEach(func() {
			failureMessage = "error message " + uuid.New().String()
			mockSageMakerClientBuilder.AddDescribeHyperParameterTuningJobErrorResponse("Exception", failureMessage, 500, "request id")
		})
		It("Requeues immediately", func() {
			ExpectRequeueImmediately(reconcileResult, reconcileError)
		})
		It("Updates status", func() {
			ExpectAdditionalToContain(tuningJob, failureMessage)
			ExpectStatusToBe(tuningJob, ReconcilingTuningJobStatus)
		})
	})
	Context("HyperParameterTuningJob does not exist", func() {
		BeforeEach(func() {
			mockSageMakerClientBuilder.
				AddDescribeHyperParameterTuningJobErrorResponse(clientwrapper.DescribeHyperParameterTuningJob404Code, clientwrapper.DescribeHyperParameterTuningJob404MessagePrefix, 400, "request id")
		})
		Context("HasDeletionTimestamp", func() {
			BeforeEach(func() {
				shouldHaveDeletionTimestamp = true
				shouldHaveFinalizer = true
			})
			It("Removes finalizer and deletes HyperParameterTuningJob", func() {
				ExpectHyperParameterTuningJobToBeDeleted(tuningJob)
			})
			It("Requeues after interval", func() {
				ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
			})
		})
		Context("!HasDeletionTimestamp", func() {
			BeforeEach(func() {
				mockSageMakerClientBuilder.
					AddCreateHyperParameterTuningJobResponse(sagemaker.CreateHyperParameterTuningJobOutput{}).
					AddDescribeHyperParameterTuningJobResponse(CreateDescribeOutputWithOnlyStatus(aws.String(sagemaker.HyperParameterTuningJobStatusInProgress), bestTrainingJob, statusCounters))
				shouldHaveDeletionTimestamp = false
				shouldHaveFinalizer = true
			})
			It("Creates a HyperParameterTuningJob", func() {
				req := receivedRequests.Front().Next().Value
				ExpectRequestToCreateHyperParameterTuningJob(req, controllers.GetGeneratedJobName(tuningJob.ObjectMeta.GetUID(), tuningJob.ObjectMeta.GetName(), MaxHyperParameterTuningJobNameLength))
			})
			It("Requeues after interval", func() {
				ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
			})
			It("Updates status", func() {
				ExpectStatusToBe(tuningJob, string(sagemaker.HyperParameterTuningJobStatusInProgress))
			})
			Context("Spec defines HyperParameterTuningJobName", func() {
				BeforeEach(func() {
					tuningJob.Spec.HyperParameterTuningJobName = ToStringPtr("tuning-job-name")
				})
				It("Creates a HyperParameterTuningJob", func() {
					req := receivedRequests.Front().Next().Value
					ExpectRequestToCreateHyperParameterTuningJob(req, "tuning-job-name")
				})
			})
		})
	})
	Context("HyperParameterTuningJob exists", func() {
		var expectedStatus *string
		BeforeEach(func() {
			shouldHaveFinalizer = true
		})
		Context("HyperParameterTuningJob has status 'InProgress'", func() {
			BeforeEach(func() {
				expectedStatus = aws.String(sagemaker.HyperParameterTuningJobStatusInProgress)
				mockSageMakerClientBuilder.
					AddDescribeHyperParameterTuningJobResponse(CreateDescribeOutputWithOnlyStatus(expectedStatus, bestTrainingJob, statusCounters))
			})
			When("!HasDeletionTimestamp", func() {
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Updates status", func() {
					ExpectStatusToBe(tuningJob, *expectedStatus)
				})
				It("Attempts to spawn missing Training Jobs", func() {
					ExpectNumberOfSpawnMissingTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstSpawnMissingTrainingJobsCallToHaveHPOJob(*jobSpawner, *tuningJob)
				})
				It("Updates the BestTrainingJob in the status", func() {
					ExpectBestTrainingJobToBe(tuningJob, bestTrainingJob)
				})
				It("Updates the TrainingJobStatusCounters in the status", func() {
					ExpectTrainingJobStatusCountersToBe(tuningJob, statusCounters)
				})
				Context("Does not have a finalizer", func() {
					BeforeEach(func() {
						shouldHaveFinalizer = false
					})
					It("Adds a finalizer", func() {
						ExpectToHaveFinalizer(tuningJob, controllers.SageMakerResourceFinalizerName)
					})
				})
			})
			When("HasDeletionTimestamp", func() {
				BeforeEach(func() {
					shouldHaveDeletionTimestamp = true
					expectedStatus = aws.String(sagemaker.HyperParameterTuningJobStatusStopping)
					mockSageMakerClientBuilder.
						AddStopHyperParameterTuningJobResponse(sagemaker.StopHyperParameterTuningJobOutput{}).
						AddDescribeHyperParameterTuningJobResponse(CreateDescribeOutputWithOnlyStatus(expectedStatus, bestTrainingJob, statusCounters))
				})
				It("Stops the HyperParameterTuningJob", func() {
					ExpectRequestToStopHyperParameterTuningJob(receivedRequests.Front().Next().Value, tuningJob)
				})
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Updates status to 'Stopping' and does not delete HyperParameterTuningJob", func() {
					ExpectStatusToBe(tuningJob, *expectedStatus)
				})
			})
		})
		Context("HyperParameterTuningJob has status 'Stopping'", func() {
			BeforeEach(func() {
				expectedStatus = aws.String(sagemaker.HyperParameterTuningJobStatusStopping)
				mockSageMakerClientBuilder.
					AddDescribeHyperParameterTuningJobResponse(CreateDescribeOutputWithOnlyStatus(expectedStatus, bestTrainingJob, statusCounters))
			})
			When("!HasDeletionTimestamp", func() {
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Updates status", func() {
					ExpectStatusToBe(tuningJob, *expectedStatus)
				})
				It("Attempts to spawn missing Training Jobs", func() {
					ExpectNumberOfSpawnMissingTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstSpawnMissingTrainingJobsCallToHaveHPOJob(*jobSpawner, *tuningJob)
				})
				It("Updates the BestTrainingJob in the status", func() {
					ExpectBestTrainingJobToBe(tuningJob, bestTrainingJob)
				})
				It("Updates the TrainingJobStatusCounters in the status", func() {
					ExpectTrainingJobStatusCountersToBe(tuningJob, statusCounters)
				})
				Context("Does not have a finalizer", func() {
					BeforeEach(func() {
						shouldHaveFinalizer = false
					})
					It("Adds a finalizer", func() {
						ExpectToHaveFinalizer(tuningJob, controllers.SageMakerResourceFinalizerName)
					})
				})
			})
			When("HasDeletionTimestamp", func() {
				BeforeEach(func() {
					shouldHaveDeletionTimestamp = true
				})
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Updates status to 'Stopping' and does not delete HyperParameterTuningJob", func() {
					ExpectStatusToBe(tuningJob, string(sagemaker.HyperParameterTuningJobStatusStopping))
				})
			})
		})
		Context("HyperParameterTuningJob has status 'Failed'", func() {
			var failureReason string
			BeforeEach(func() {
				expectedStatus = aws.String(sagemaker.HyperParameterTuningJobStatusFailed)
				failureReason = "Failure within the hpo job"
				describeOutput := CreateDescribeOutputWithOnlyStatus(expectedStatus, bestTrainingJob, statusCounters)
				describeOutput.FailureReason = ToStringPtr(failureReason)
				mockSageMakerClientBuilder.
					AddDescribeHyperParameterTuningJobResponse(describeOutput)
			})
			When("!HasDeletionTimestamp", func() {
				It("Doesn't requeue", func() {
					ExpectNoRequeue(reconcileResult, reconcileError)
				})
				It("Updates status", func() {
					ExpectStatusToBe(tuningJob, *expectedStatus)
				})
				It("Has the additional field set", func() {
					ExpectAdditionalToContain(tuningJob, failureReason)
				})
				It("Attempts to spawn missing Training Jobs", func() {
					ExpectNumberOfSpawnMissingTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstSpawnMissingTrainingJobsCallToHaveHPOJob(*jobSpawner, *tuningJob)
				})
				It("Updates the BestTrainingJob in the status", func() {
					ExpectBestTrainingJobToBe(tuningJob, bestTrainingJob)
				})
				It("Updates the TrainingJobStatusCounters in the status", func() {
					ExpectTrainingJobStatusCountersToBe(tuningJob, statusCounters)
				})
				Context("Does not have a finalizer", func() {
					BeforeEach(func() {
						shouldHaveFinalizer = false
					})
					It("Adds a finalizer", func() {
						ExpectToHaveFinalizer(tuningJob, controllers.SageMakerResourceFinalizerName)
					})
				})
			})
			When("HasDeletionTimestamp", func() {
				BeforeEach(func() {
					shouldHaveDeletionTimestamp = true
				})
				It("Deletes the tuning job", func() {
					ExpectHyperParameterTuningJobToBeDeleted(tuningJob)
				})
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Attempts to delete all spawned training jobs", func() {
					ExpectNumberOfDeleteSpawnedTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstDeleteSpawnedTrainingJobsToHaveHPOJob(*jobSpawner, *tuningJob)
				})
				Context("Failed to delete spawned training jobs", func() {
					BeforeEach(func() {
						jobSpawner = &mockTrackingHPOTrainingJobSpawner{
							deleteShouldFail:               true,
							spawnMissingTrainingJobsCalls:  &List{},
							deleteSpawnedTrainingJobsCalls: &List{},
						}
					})
					It("Requeue immediately", func() {
						ExpectRequeueImmediately(reconcileResult, reconcileError)
					})
				})
			})
		})
		Context("HyperParameterTuningJob has status 'Stopped'", func() {
			BeforeEach(func() {
				expectedStatus = aws.String(sagemaker.HyperParameterTuningJobStatusStopped)
				mockSageMakerClientBuilder.
					AddDescribeHyperParameterTuningJobResponse(CreateDescribeOutputWithOnlyStatus(expectedStatus, bestTrainingJob, statusCounters))
			})
			When("!HasDeletionTimestamp", func() {
				It("Doesn't requeue", func() {
					ExpectNoRequeue(reconcileResult, reconcileError)
				})
				It("Updates status", func() {
					ExpectStatusToBe(tuningJob, *expectedStatus)
				})
				It("Attempts to spawn missing Training Jobs", func() {
					ExpectNumberOfSpawnMissingTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstSpawnMissingTrainingJobsCallToHaveHPOJob(*jobSpawner, *tuningJob)
				})
				It("Updates the BestTrainingJob in the status", func() {
					ExpectBestTrainingJobToBe(tuningJob, bestTrainingJob)
				})
				It("Updates the TrainingJobStatusCounters in the status", func() {
					ExpectTrainingJobStatusCountersToBe(tuningJob, statusCounters)
				})
				Context("Does not have a finalizer", func() {
					BeforeEach(func() {
						shouldHaveFinalizer = false
					})
					It("Adds a finalizer", func() {
						ExpectToHaveFinalizer(tuningJob, controllers.SageMakerResourceFinalizerName)
					})
				})
			})
			When("HasDeletionTimestamp", func() {
				BeforeEach(func() {
					shouldHaveDeletionTimestamp = true
				})
				It("Deletes the tuning job", func() {
					ExpectHyperParameterTuningJobToBeDeleted(tuningJob)
				})
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Attempts to delete all spawned training jobs", func() {
					ExpectNumberOfDeleteSpawnedTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstDeleteSpawnedTrainingJobsToHaveHPOJob(*jobSpawner, *tuningJob)
				})
			})
		})
		Context("HyperParameterTuningJob has status 'Completed'", func() {
			BeforeEach(func() {
				expectedStatus = aws.String(sagemaker.HyperParameterTuningJobStatusCompleted)
				mockSageMakerClientBuilder.
					AddDescribeHyperParameterTuningJobResponse(CreateDescribeOutputWithOnlyStatus(expectedStatus, bestTrainingJob, statusCounters))
			})
			When("!HasDeletionTimestamp", func() {
				It("Doesn't requeue", func() {
					ExpectNoRequeue(reconcileResult, reconcileError)
				})
				It("Updates status", func() {
					ExpectStatusToBe(tuningJob, *expectedStatus)
				})
				It("Attempts to spawn missing Training Jobs", func() {
					ExpectNumberOfSpawnMissingTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstSpawnMissingTrainingJobsCallToHaveHPOJob(*jobSpawner, *tuningJob)
				})
				It("Updates the BestTrainingJob in the status", func() {
					ExpectBestTrainingJobToBe(tuningJob, bestTrainingJob)
				})
				It("Updates the TrainingJobStatusCounters in the status", func() {
					ExpectTrainingJobStatusCountersToBe(tuningJob, statusCounters)
				})
				Context("Does not have a finalizer", func() {
					BeforeEach(func() {
						shouldHaveFinalizer = false
					})
					It("Adds a finalizer", func() {
						ExpectToHaveFinalizer(tuningJob, controllers.SageMakerResourceFinalizerName)
					})
				})
			})
			When("HasDeletionTimestamp", func() {
				BeforeEach(func() {
					shouldHaveDeletionTimestamp = true
				})
				It("Deletes the tuning job", func() {
					ExpectHyperParameterTuningJobToBeDeleted(tuningJob)
				})
				It("Requeues after interval", func() {
					ExpectRequeueAfterInterval(reconcileResult, reconcileError, pollDuration)
				})
				It("Attempts to delete all spawned training jobs", func() {
					ExpectNumberOfDeleteSpawnedTrainingJobsCallsToEqual(*jobSpawner, 1)
					ExpectFirstDeleteSpawnedTrainingJobsToHaveHPOJob(*jobSpawner, *tuningJob)
				})
			})
		})
	})
})
type mockTrackingHPOTrainingJobSpawner struct {
	deleteShouldFail bool
	spawnMissingTrainingJobsCalls *List
	deleteSpawnedTrainingJobsCalls *List
}
var _ HPOTrainingJobSpawner = (*mockTrackingHPOTrainingJobSpawner)(nil)
func (s mockTrackingHPOTrainingJobSpawner) SpawnMissingTrainingJobs(_ context.Context, job hpojobv1.HyperparameterTuningJob) {
	s.spawnMissingTrainingJobsCalls.PushBack(job)
}
func (s mockTrackingHPOTrainingJobSpawner) DeleteSpawnedTrainingJobs(_ context.Context, job hpojobv1.HyperparameterTuningJob) error {
	s.deleteSpawnedTrainingJobsCalls.PushBack(job)
	if s.deleteShouldFail {
		return errors.New("failed delete spawned training jobs")
	}
	return nil
}
func createMockHPOTrainingJobSpawnerProvider(spawner HPOTrainingJobSpawner) HPOTrainingJobSpawnerProvider {
	return func(_ client.Client, _ logr.Logger, _ clientwrapper.SageMakerClientWrapper) HPOTrainingJobSpawner {
		return spawner
	}
}
func createReconciler(k8sClient k8sclient.Client, sageMakerClient sagemakeriface.SageMakerAPI, pollIntervalStr string, hpoJobSpawner HPOTrainingJobSpawner) *Reconciler {
	pollInterval := ParseDurationOrFail(pollIntervalStr)
	return &Reconciler{
		Client:                      k8sClient,
		Log:                         ctrl.Log,
		PollInterval:                pollInterval,
		createSageMakerClient:       CreateMockSageMakerClientWrapperProvider(sageMakerClient),
		awsConfigLoader:             CreateMockAWSConfigLoader(),
		createHPOTrainingJobSpawner: createMockHPOTrainingJobSpawnerProvider(hpoJobSpawner),
	}
}
func createHyperParameterTuningJobWithGeneratedNames() *hpojobv1.HyperparameterTuningJob {
	k8sName := "hyperparameter-tuning-job-" + uuid.New().String()
	k8sNamespace := "namespace-" + uuid.New().String()
	CreateMockNamespace(context.Background(), k8sClient, k8sNamespace)
	return createHyperParameterTuningJob(k8sName, k8sNamespace)
}
func createHyperParameterTuningJob(k8sName, k8sNamespace string) *hpojobv1.HyperparameterTuningJob {
	return &hpojobv1.HyperparameterTuningJob{
		ObjectMeta: metav1.ObjectMeta{
			Name:      k8sName,
			Namespace: k8sNamespace,
		},
		Spec: hpojobv1.HyperparameterTuningJobSpec{
			Region: ToStringPtr("region-xyz"),
			HyperParameterTuningJobConfig: &commonv1.HyperParameterTuningJobConfig{
				ResourceLimits: &commonv1.ResourceLimits{
					MaxNumberOfTrainingJobs: ToInt64Ptr(15),
					MaxParallelTrainingJobs: ToInt64Ptr(5),
				},
				Strategy: "strategy-type",
			},
			TrainingJobDefinition: &commonv1.HyperParameterTrainingJobDefinition{
				AlgorithmSpecification: &commonv1.HyperParameterAlgorithmSpecification{
					TrainingInputMode: "File",
				},
				OutputDataConfig: &commonv1.OutputDataConfig{
					S3OutputPath: ToStringPtr("s3://outputpath"),
				},
				ResourceConfig: &commonv1.ResourceConfig{
					InstanceCount:  ToInt64Ptr(1),
					InstanceType:   "xyz",
					VolumeSizeInGB: ToInt64Ptr(50),
				},
				RoleArn:           ToStringPtr("xxxxxxxxxxxxxxxxxxxx"),
				StoppingCondition: &commonv1.StoppingCondition{},
			},
		},
	}
}
func AddFinalizer(tuningJob *hpojobv1.HyperparameterTuningJob) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).ToNot(HaveOccurred())
	actual.ObjectMeta.Finalizers = []string{controllers.SageMakerResourceFinalizerName}
	Expect(k8sClient.Update(context.Background(), &actual)).To(Succeed())
}
func SetDeletionTimestamp(tuningJob *hpojobv1.HyperparameterTuningJob) {
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, tuningJob)
	Expect(err).ToNot(HaveOccurred())
	Expect(k8sClient.Delete(context.Background(), tuningJob)).To(Succeed())
}
func ExpectAdditionalToContain(tuningJob *hpojobv1.HyperparameterTuningJob, substring string) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).ToNot(HaveOccurred())
	Expect(actual.Status.Additional).To(ContainSubstring(substring))
}
func ExpectStatusToBe(tuningJob *hpojobv1.HyperparameterTuningJob, primaryStatus string) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).ToNot(HaveOccurred())
	Expect(string(actual.Status.HyperParameterTuningJobStatus)).To(Equal(primaryStatus))
}
func ExpectToHaveFinalizer(tuningJob *hpojobv1.HyperparameterTuningJob, finalizer string) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).ToNot(HaveOccurred())
	Expect(actual.ObjectMeta.Finalizers).To(ContainElement(finalizer))
}
func ExpectHyperParameterTuningJobToBeDeleted(tuningJob *hpojobv1.HyperparameterTuningJob) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).To(HaveOccurred())
	Expect(apierrs.IsNotFound(err)).To(Equal(true))
}
func ExpectBestTrainingJobToBe(tuningJob *hpojobv1.HyperparameterTuningJob, job *sagemaker.HyperParameterTrainingJobSummary) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).ToNot(HaveOccurred())
	Expect(*actual.Status.BestTrainingJob.TrainingJobName).To(Equal(*job.TrainingJobName))
}
func ExpectTrainingJobStatusCountersToBe(tuningJob *hpojobv1.HyperparameterTuningJob, counters *sagemaker.TrainingJobStatusCounters) {
	var actual hpojobv1.HyperparameterTuningJob
	err := k8sClient.Get(context.Background(), types.NamespacedName{
		Namespace: tuningJob.ObjectMeta.Namespace,
		Name:      tuningJob.ObjectMeta.Name,
	}, &actual)
	Expect(err).ToNot(HaveOccurred())
	Expect(*actual.Status.TrainingJobStatusCounters.Completed).To(Equal(*counters.Completed))
}
func CreateDescribeOutputWithOnlyStatus(status *string, bestTrainingJob *sagemaker.HyperParameterTrainingJobSummary, statusCounters *sagemaker.TrainingJobStatusCounters) sagemaker.DescribeHyperParameterTuningJobOutput {
	return sagemaker.DescribeHyperParameterTuningJobOutput{
		HyperParameterTuningJobStatus: status,
		BestTrainingJob:               bestTrainingJob,
		TrainingJobStatusCounters:     statusCounters,
	}
}