From d124b8b9eebeeca5c046e33b45de200578da1517 Mon Sep 17 00:00:00 2001 From: Ce Gao Date: Wed, 15 May 2019 15:19:54 +0800 Subject: [PATCH] feat(trial): Add test --- .../{crds.yaml => crd-experiment.yaml} | 15 ---- .../v1alpha2/katib-controller/crd-trial.yaml | 14 +++ .../trial/trial_controller_suite_test.go | 76 +++++++++++++++++ .../v1alpha2/trial/trial_controller_test.go | 85 +++++++++++++++++++ 4 files changed, 175 insertions(+), 15 deletions(-) rename manifests/v1alpha2/katib-controller/{crds.yaml => crd-experiment.yaml} (51%) create mode 100644 manifests/v1alpha2/katib-controller/crd-trial.yaml create mode 100644 pkg/controller/v1alpha2/trial/trial_controller_suite_test.go create mode 100644 pkg/controller/v1alpha2/trial/trial_controller_test.go diff --git a/manifests/v1alpha2/katib-controller/crds.yaml b/manifests/v1alpha2/katib-controller/crd-experiment.yaml similarity index 51% rename from manifests/v1alpha2/katib-controller/crds.yaml rename to manifests/v1alpha2/katib-controller/crd-experiment.yaml index 76ddc8aadf3..e26b1fc317b 100644 --- a/manifests/v1alpha2/katib-controller/crds.yaml +++ b/manifests/v1alpha2/katib-controller/crd-experiment.yaml @@ -12,18 +12,3 @@ spec: kind: Experiment singular: experiment plural: experiments ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: trials.kubeflow.org -spec: - group: kubeflow.org - version: v1alpha2 - scope: Namespaced - subresources: - status: {} - names: - kind: Trial - singular: trial - plural: trials diff --git a/manifests/v1alpha2/katib-controller/crd-trial.yaml b/manifests/v1alpha2/katib-controller/crd-trial.yaml new file mode 100644 index 00000000000..ac8344e2f5f --- /dev/null +++ b/manifests/v1alpha2/katib-controller/crd-trial.yaml @@ -0,0 +1,14 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: trials.kubeflow.org +spec: + group: kubeflow.org + version: v1alpha2 + scope: Namespaced + subresources: + status: {} + names: + kind: Trial + singular: trial + plural: trials diff --git a/pkg/controller/v1alpha2/trial/trial_controller_suite_test.go b/pkg/controller/v1alpha2/trial/trial_controller_suite_test.go new file mode 100644 index 00000000000..3a9943e53c1 --- /dev/null +++ b/pkg/controller/v1alpha2/trial/trial_controller_suite_test.go @@ -0,0 +1,76 @@ +/* +Copyright 2019 The Kubernetes Authors. + +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. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trial + +import ( + stdlog "log" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/kubeflow/katib/pkg/api/operators/apis" +) + +var cfg *rest.Config + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "manifests", "v1alpha2", "katib-controller")}, + } + apis.AddToScheme(scheme.Scheme) + + var err error + if cfg, err = t.Start(); err != nil { + stdlog.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} + +// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and +// writes the request to requests after Reconcile is finished. +func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) { + requests := make(chan reconcile.Request) + fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) { + result, err := inner.Reconcile(req) + requests <- req + return result, err + }) + return fn, requests +} + +// StartTestManager adds recFn +func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) { + stop := make(chan struct{}) + wg := &sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred()) + }() + return stop, wg +} diff --git a/pkg/controller/v1alpha2/trial/trial_controller_test.go b/pkg/controller/v1alpha2/trial/trial_controller_test.go new file mode 100644 index 00000000000..8671cfac0a1 --- /dev/null +++ b/pkg/controller/v1alpha2/trial/trial_controller_test.go @@ -0,0 +1,85 @@ +package trial + +import ( + "testing" + "time" + + "github.com/onsi/gomega" + "golang.org/x/net/context" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + trialsv1alpha2 "github.com/kubeflow/katib/pkg/api/operators/apis/trial/v1alpha2" +) + +const ( + trialName = "foo" + namespace = "default" + + timeout = time.Second * 5 +) + +var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: trialName, Namespace: namespace}} + +func TestCreate(t *testing.T) { + g := gomega.NewGomegaWithT(t) + instance := newFakeTrial() + + // Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a + // channel when it is finished. + mgr, err := manager.New(cfg, manager.Options{}) + g.Expect(err).NotTo(gomega.HaveOccurred()) + c := mgr.GetClient() + + recFn, requests := SetupTestReconcile(newReconciler(mgr)) + g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred()) + + stopMgr, mgrStopped := StartTestManager(mgr, g) + + defer func() { + close(stopMgr) + mgrStopped.Wait() + }() + + // Create the Trial object and expect the Reconcile and Deployment to be created + err = c.Create(context.TODO(), instance) + // The instance object may not be a valid object because it might be missing some required fields. + // Please modify the instance object by adding required fields and then remove the following if statement. + if apierrors.IsInvalid(err) { + t.Logf("failed to create object, got an invalid object error: %v", err) + return + } + g.Expect(err).NotTo(gomega.HaveOccurred()) + defer c.Delete(context.TODO(), instance) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) +} + +func newFakeTrial() *trialsv1alpha2.Trial { + t := &trialsv1alpha2.Trial{ + ObjectMeta: metav1.ObjectMeta{ + Name: trialName, + Namespace: namespace, + }, + Spec: trialsv1alpha2.TrialSpec{ + RunSpec: ` +apiVersion: "kubeflow.org/v1beta1" +kind: "TFJob" +metadata: + name: "dist-mnist-for-e2e-test" +spec: + tfReplicaSpecs: + Worker: + replicas: 1 + restartPolicy: Never + template: + spec: + containers: + - name: tensorflow + image: gaocegege/mnist:1`, + }, + } + return t +}