-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds initial test framework and sample memcached tests that use the framework.
- Loading branch information
1 parent
fa4ea18
commit b19e56f
Showing
14 changed files
with
802 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright 2018 The Operator-SDK 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 cmd | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/operator-framework/operator-sdk/pkg/test" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
testLocation string | ||
kubeconfig string | ||
crdManifestPath string | ||
opManifestPath string | ||
rbacManifestPath string | ||
verbose bool | ||
) | ||
|
||
// TODO: allow users to pass flags through to `go test` | ||
func NewTestCmd() *cobra.Command { | ||
testCmd := &cobra.Command{ | ||
Use: "test --test-location <path to tests directory> [flags]", | ||
Short: "Run End-To-End tests", | ||
Run: testFunc, | ||
} | ||
defaultKubeConfig := "" | ||
homedir, ok := os.LookupEnv("HOME") | ||
if ok { | ||
defaultKubeConfig = homedir + "/.kube/config" | ||
} | ||
testCmd.Flags().StringVarP(&testLocation, "test-location", "t", "", "Location of test files (e.g. ./test/e2e/)") | ||
testCmd.MarkFlagRequired("test-location") | ||
testCmd.Flags().StringVarP(&kubeconfig, "kubeconfig", "k", defaultKubeConfig, "Kubeconfig path") | ||
testCmd.Flags().StringVarP(&crdManifestPath, "crd", "c", "deploy/crd.yaml", "Path to CRD manifest") | ||
testCmd.Flags().StringVarP(&opManifestPath, "operator", "o", "deploy/operator.yaml", "Path to operator manifest") | ||
testCmd.Flags().StringVarP(&rbacManifestPath, "rbac", "r", "deploy/rbac.yaml", "Path to RBAC manifest") | ||
testCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose go test") | ||
|
||
return testCmd | ||
} | ||
|
||
func testFunc(cmd *cobra.Command, args []string) { | ||
testArgs := []string{"test", testLocation + "/..."} | ||
if verbose { | ||
testArgs = append(testArgs, "-v") | ||
} | ||
testArgs = append(testArgs, "-"+test.KubeConfigFlag, kubeconfig) | ||
testArgs = append(testArgs, "-"+test.CrdManPathFlag, crdManifestPath) | ||
testArgs = append(testArgs, "-"+test.OpManPathFlag, opManifestPath) | ||
testArgs = append(testArgs, "-"+test.RbacManPathFlag, rbacManifestPath) | ||
testArgs = append(testArgs, "-"+test.ProjRootFlag, mustGetwd()) | ||
execCmd(os.Stdout, "go", testArgs...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright 2018 The Operator-SDK 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 test | ||
|
||
import ( | ||
"log" | ||
"strconv" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
"k8s.io/client-go/rest" | ||
) | ||
|
||
type TestCtx struct { | ||
ID string | ||
CleanUpFns []finalizerFn | ||
Namespace string | ||
CRClient *rest.RESTClient | ||
} | ||
|
||
type finalizerFn func() error | ||
|
||
func NewTestCtx(t *testing.T) TestCtx { | ||
var prefix string | ||
if t != nil { | ||
// TestCtx is used among others for namespace names where '/' is forbidden | ||
prefix = strings.TrimPrefix( | ||
strings.Replace( | ||
strings.ToLower(t.Name()), | ||
"/", | ||
"-", | ||
-1, | ||
), | ||
"test", | ||
) | ||
} else { | ||
prefix = "main" | ||
} | ||
|
||
id := prefix + "-" + strconv.FormatInt(time.Now().Unix(), 10) | ||
return TestCtx{ | ||
ID: id, | ||
} | ||
} | ||
|
||
func (ctx *TestCtx) GetID() string { | ||
return ctx.ID | ||
} | ||
|
||
func (ctx *TestCtx) Cleanup(t *testing.T) { | ||
for i := len(ctx.CleanUpFns) - 1; i >= 0; i-- { | ||
err := ctx.CleanUpFns[i]() | ||
if err != nil { | ||
t.Errorf("a cleanup function failed with error: %v\n", err) | ||
} | ||
} | ||
} | ||
|
||
// CleanupNoT is a modified version of Cleanup; does not use t for logging, instead uses log | ||
// intended for use by MainEntry, which does not have a testing.T | ||
func (ctx *TestCtx) CleanupNoT() { | ||
failed := false | ||
for i := len(ctx.CleanUpFns) - 1; i >= 0; i-- { | ||
err := ctx.CleanUpFns[i]() | ||
if err != nil { | ||
failed = true | ||
log.Printf("a cleanup function failed with error: %v\n", err) | ||
} | ||
} | ||
if failed { | ||
log.Fatal("a cleanup function failed") | ||
} | ||
} | ||
|
||
func (ctx *TestCtx) AddFinalizerFn(fn finalizerFn) { | ||
ctx.CleanUpFns = append(ctx.CleanUpFns, fn) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Copyright 2018 The Operator-SDK 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 test | ||
|
||
import ( | ||
"fmt" | ||
|
||
extensions "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" | ||
extscheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/runtime/serializer" | ||
"k8s.io/client-go/kubernetes" | ||
cgoscheme "k8s.io/client-go/kubernetes/scheme" | ||
"k8s.io/client-go/rest" | ||
"k8s.io/client-go/tools/clientcmd" | ||
dynclient "sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
var Global *Framework | ||
|
||
type Framework struct { | ||
KubeConfig *rest.Config | ||
KubeClient kubernetes.Interface | ||
ExtensionsClient *extensions.Clientset | ||
DynamicClient dynclient.Client | ||
DynamicDecoder runtime.Decoder | ||
CrdManPath *string | ||
OpManPath *string | ||
RbacManPath *string | ||
} | ||
|
||
func setup(kubeconfigPath, crdManPath, opManPath, rbacManPath *string) error { | ||
kubeconfig, err := clientcmd.BuildConfigFromFlags("", *kubeconfigPath) | ||
if err != nil { | ||
return fmt.Errorf("failed to build the kubeconfig: %v", err) | ||
} | ||
kubeclient, err := kubernetes.NewForConfig(kubeconfig) | ||
if err != nil { | ||
return fmt.Errorf("failed to build the kubeclient: %v", err) | ||
} | ||
extensionsClient, err := extensions.NewForConfig(kubeconfig) | ||
if err != nil { | ||
return fmt.Errorf("failed to build the extensionsClient: %v", err) | ||
} | ||
scheme := runtime.NewScheme() | ||
cgoscheme.AddToScheme(scheme) | ||
extscheme.AddToScheme(scheme) | ||
dynClient, err := dynclient.New(kubeconfig, dynclient.Options{Scheme: scheme}) | ||
if err != nil { | ||
return fmt.Errorf("failed to build the dynamic client: %v", err) | ||
} | ||
dynDec := serializer.NewCodecFactory(scheme).UniversalDeserializer() | ||
Global = &Framework{ | ||
KubeConfig: kubeconfig, | ||
KubeClient: kubeclient, | ||
ExtensionsClient: extensionsClient, | ||
DynamicClient: dynClient, | ||
DynamicDecoder: dynDec, | ||
CrdManPath: crdManPath, | ||
OpManPath: opManPath, | ||
RbacManPath: rbacManPath, | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2018 The Operator-SDK 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 test | ||
|
||
import ( | ||
"flag" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"testing" | ||
) | ||
|
||
const ( | ||
ProjRootFlag = "root" | ||
KubeConfigFlag = "kubeconfig" | ||
CrdManPathFlag = "crd" | ||
OpManPathFlag = "op" | ||
RbacManPathFlag = "rbac" | ||
) | ||
|
||
func MainEntry(m *testing.M) { | ||
projRoot := flag.String("root", "", "path to project root") | ||
kubeconfigPath := flag.String("kubeconfig", "", "path to kubeconfig") | ||
crdManPath := flag.String("crd", "", "path to crd manifest") | ||
opManPath := flag.String("op", "", "path to operator manifest") | ||
rbacManPath := flag.String("rbac", "", "path to rbac manifest") | ||
flag.Parse() | ||
// go test always runs from the test directory; change to project root | ||
err := os.Chdir(*projRoot) | ||
if err != nil { | ||
log.Fatalf("failed to change directory to project root: %v", err) | ||
} | ||
if err := setup(kubeconfigPath, crdManPath, opManPath, rbacManPath); err != nil { | ||
log.Fatalf("failed to set up framework: %v", err) | ||
} | ||
// setup context to use when setting up crd | ||
ctx := NewTestCtx(nil) | ||
// os.Exit stops the program before the deferred functions run | ||
// to fix this, we put the exit in the defer as well | ||
defer func() { | ||
exitCode := m.Run() | ||
ctx.CleanupNoT() | ||
os.Exit(exitCode) | ||
}() | ||
// create crd | ||
crdYAML, err := ioutil.ReadFile(*Global.CrdManPath) | ||
if err != nil { | ||
log.Fatalf("failed to read crd file: %v", err) | ||
} | ||
err = ctx.CreateFromYAML(crdYAML) | ||
if err != nil { | ||
log.Fatalf("failed to create crd resource: %v", err) | ||
} | ||
} |
Oops, something went wrong.