Add integration testing framework and a basic conversion test
Signed-off-by: James Munnelly <james@munnelly.eu>
This commit is contained in:
parent
dc6920df97
commit
4e5f9bc31d
@ -81,6 +81,7 @@ filegroup(
|
||||
"//pkg/webhook:all-srcs",
|
||||
"//test/acme/dns:all-srcs",
|
||||
"//test/e2e:all-srcs",
|
||||
"//test/integration:all-srcs",
|
||||
"//test/unit/gen:all-srcs",
|
||||
"//test/unit/listers:all-srcs",
|
||||
],
|
||||
|
||||
@ -44,6 +44,9 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//deploy/charts/cert-manager/crds:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
13
deploy/charts/cert-manager/crds/BUILD.bazel
Normal file
13
deploy/charts/cert-manager/crds/BUILD.bazel
Normal file
@ -0,0 +1,13 @@
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@ -47,7 +47,7 @@ cd "${REPO_ROOT}"
|
||||
out="./deploy/manifests/00-crds.yaml"
|
||||
rm "$out" || true
|
||||
touch "$out"
|
||||
for file in $(find "./deploy/charts/cert-manager/crds" -type f | sort -V); do
|
||||
for file in $(find "./deploy/charts/cert-manager/crds" -name '*.yaml' -type f | sort -V); do
|
||||
# concatenate all files while removing blank (^$) lines
|
||||
< "$file" sed '/^$$/d' >> "$out"
|
||||
printf -- "---\n" >> "$out"
|
||||
|
||||
17
test/integration/BUILD.bazel
Normal file
17
test/integration/BUILD.bazel
Normal file
@ -0,0 +1,17 @@
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//test/integration/conversion:all-srcs",
|
||||
"//test/integration/framework:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
30
test/integration/conversion/BUILD.bazel
Normal file
30
test/integration/conversion/BUILD.bazel
Normal file
@ -0,0 +1,30 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["conversion_test.go"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/apis/certmanager/v1alpha2:go_default_library",
|
||||
"//pkg/apis/certmanager/v1alpha3:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//test/integration/framework:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
|
||||
"@io_k8s_sigs_controller_runtime//pkg/client:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
91
test/integration/conversion/conversion_test.go
Normal file
91
test/integration/conversion/conversion_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2020 The Jetstack cert-manager contributors.
|
||||
|
||||
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 conversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/api"
|
||||
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
|
||||
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha3"
|
||||
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
|
||||
"github.com/jetstack/cert-manager/test/integration/framework"
|
||||
)
|
||||
|
||||
func TestConversion(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
input runtime.Object
|
||||
output runtime.Object
|
||||
}{
|
||||
"should convert Certificates from v1alpha2 to v1alpha3": {
|
||||
input: &v1alpha2.Certificate{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v1alpha2.CertificateSpec{
|
||||
SecretName: "something",
|
||||
IssuerRef: cmmeta.ObjectReference{
|
||||
Name: "issuername",
|
||||
},
|
||||
},
|
||||
},
|
||||
output: &v1alpha3.Certificate{},
|
||||
},
|
||||
"should convert CertificateRequest from v1alpha2 to v1alpha3": {
|
||||
input: &v1alpha2.CertificateRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v1alpha2.CertificateRequestSpec{
|
||||
// validating webhook isn't currently configured in test
|
||||
// environment so this passes validation.
|
||||
CSRPEM: []byte("a"),
|
||||
IssuerRef: cmmeta.ObjectReference{
|
||||
Name: "issuername",
|
||||
},
|
||||
},
|
||||
},
|
||||
output: &v1alpha3.CertificateRequest{},
|
||||
},
|
||||
}
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
config, stop := framework.RunControlPlane(t)
|
||||
defer stop()
|
||||
|
||||
cl, err := client.New(config, client.Options{Scheme: api.Scheme})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cl.Create(context.Background(), test.input); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
meta := test.input.(metav1.ObjectMetaAccessor)
|
||||
if err := cl.Get(context.Background(), client.ObjectKey{Name: meta.GetObjectMeta().GetName(), Namespace: meta.GetObjectMeta().GetNamespace()}, test.output); err != nil {
|
||||
t.Errorf("failed to fetch object in expected API version: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
44
test/integration/framework/BUILD.bazel
Normal file
44
test/integration/framework/BUILD.bazel
Normal file
@ -0,0 +1,44 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"apiserver.go",
|
||||
"paths.go",
|
||||
],
|
||||
data = [
|
||||
"//deploy/charts/cert-manager/crds:all-srcs",
|
||||
"//hack/bin:com_coreos_etcd",
|
||||
"//hack/bin:io_kubernetes_kube-apiserver",
|
||||
"//hack/bin:kubectl",
|
||||
],
|
||||
importpath = "github.com/jetstack/cert-manager/test/integration/framework",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/webhook/app/testing:go_default_library",
|
||||
"@io_k8s_apiextensions_apiserver//pkg/apis/apiextensions:go_default_library",
|
||||
"@io_k8s_apiextensions_apiserver//pkg/apis/apiextensions/install:go_default_library",
|
||||
"@io_k8s_apiextensions_apiserver//pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime/serializer/json:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime/serializer/versioning:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/runtime:go_default_library",
|
||||
"@io_k8s_client_go//rest:go_default_library",
|
||||
"@io_k8s_sigs_controller_runtime//pkg/envtest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
149
test/integration/framework/apiserver.go
Normal file
149
test/integration/framework/apiserver.go
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright 2020 The Jetstack cert-manager contributors.
|
||||
|
||||
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 framework
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiextensionsinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
jsonserializer "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
|
||||
webhooktesting "github.com/jetstack/cert-manager/cmd/webhook/app/testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Set environment variables for controller-runtime's envtest package.
|
||||
// This is done once as we cannot scope environment variables to a single
|
||||
// invocation of RunControlPlane due to envtest's design.
|
||||
setUpEnvTestEnv()
|
||||
}
|
||||
|
||||
type StopFunc func()
|
||||
|
||||
func RunControlPlane(t *testing.T) (*rest.Config, StopFunc) {
|
||||
webhookOpts, stopWebhook := webhooktesting.StartWebhookServer(t, []string{})
|
||||
crdsDir, err := getCRDsPath()
|
||||
if err != nil {
|
||||
t.Fatalf("error determining CRD directory path: %v", err)
|
||||
}
|
||||
crds := readCustomResourcesAtPath(t, crdsDir)
|
||||
for _, crd := range crds {
|
||||
t.Logf("Found CRD with name %q", crd.Name)
|
||||
}
|
||||
patchCRDConversion(crds, webhookOpts.URL, webhookOpts.CAPEM)
|
||||
// environment variables
|
||||
env := &envtest.Environment{
|
||||
AttachControlPlaneOutput: true,
|
||||
CRDs: crds,
|
||||
}
|
||||
config, err := env.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to start control plane: %v", err)
|
||||
}
|
||||
// TODO: configure Validating and Mutating webhook
|
||||
return config, func() {
|
||||
defer stopWebhook()
|
||||
if err := env.Stop(); err != nil {
|
||||
t.Logf("failed to shut down control plane, not failing test: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
internalScheme = runtime.NewScheme()
|
||||
)
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(metav1.AddMetaToScheme(internalScheme))
|
||||
apiextensionsinstall.Install(internalScheme)
|
||||
}
|
||||
|
||||
func patchCRDConversion(crds []*v1beta1.CustomResourceDefinition, url string, caPEM []byte) {
|
||||
for _, crd := range crds {
|
||||
if crd.Spec.Conversion == nil {
|
||||
continue
|
||||
}
|
||||
if crd.Spec.Conversion.WebhookClientConfig == nil {
|
||||
continue
|
||||
}
|
||||
if crd.Spec.Conversion.WebhookClientConfig.Service == nil {
|
||||
continue
|
||||
}
|
||||
path := ""
|
||||
if crd.Spec.Conversion.WebhookClientConfig.Service.Path != nil {
|
||||
path = *crd.Spec.Conversion.WebhookClientConfig.Service.Path
|
||||
}
|
||||
url := fmt.Sprintf("%s%s", url, path)
|
||||
crd.Spec.Conversion.WebhookClientConfig.URL = &url
|
||||
crd.Spec.Conversion.WebhookClientConfig.CABundle = caPEM
|
||||
crd.Spec.Conversion.WebhookClientConfig.Service = nil
|
||||
}
|
||||
}
|
||||
|
||||
func readCustomResourcesAtPath(t *testing.T, path string) []*v1beta1.CustomResourceDefinition {
|
||||
serializer := jsonserializer.NewSerializerWithOptions(jsonserializer.DefaultMetaFactory, internalScheme, internalScheme, jsonserializer.SerializerOptions{
|
||||
Yaml: true,
|
||||
})
|
||||
converter := runtime.UnsafeObjectConvertor(internalScheme)
|
||||
codec := versioning.NewCodec(serializer, serializer, converter, internalScheme, internalScheme, internalScheme, runtime.InternalGroupVersioner, runtime.InternalGroupVersioner, internalScheme.Name())
|
||||
|
||||
var crds []*v1beta1.CustomResourceDefinition
|
||||
if err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if filepath.Ext(path) != ".yaml" {
|
||||
return nil
|
||||
}
|
||||
crd, err := readCRDAtPath(codec, converter, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
crds = append(crds, crd)
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return crds
|
||||
}
|
||||
|
||||
func readCRDAtPath(codec runtime.Codec, converter runtime.ObjectConvertor, path string) (*v1beta1.CustomResourceDefinition, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
internalCRD := &apiextensions.CustomResourceDefinition{}
|
||||
if _, _, err := codec.Decode(data, nil, internalCRD); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output := &v1beta1.CustomResourceDefinition{}
|
||||
return output, converter.Convert(internalCRD, output, nil)
|
||||
}
|
||||
70
test/integration/framework/paths.go
Normal file
70
test/integration/framework/paths.go
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2020 The Jetstack cert-manager contributors.
|
||||
|
||||
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 framework
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// setEnvTestEnv configures environment variables for controller-runtime's
|
||||
// 'envtest' package.
|
||||
func setUpEnvTestEnv() {
|
||||
maybeSetEnv("TEST_ASSET_ETCD", "etcd", "hack", "bin", "etcd")
|
||||
maybeSetEnv("TEST_ASSET_KUBE_APISERVER", "kube-apiserver", "hack", "bin", "kube-apiserver")
|
||||
maybeSetEnv("TEST_ASSET_KUBECTL", "kubectl", "hack", "bin", "kubectl")
|
||||
}
|
||||
|
||||
func maybeSetEnv(key, bin string, path ...string) {
|
||||
if os.Getenv(key) != "" {
|
||||
return
|
||||
}
|
||||
p, err := getPath(bin, path...)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf(`Failed to find integration test dependency %q.
|
||||
Either re-run this test using "bazel test //test/integration/{name}" or set the %s environment variable.`, bin, key))
|
||||
}
|
||||
os.Setenv(key, p)
|
||||
}
|
||||
|
||||
// getCRDsPath returns a path to a directory containing cert-manager CRDs.
|
||||
func getCRDsPath() (string, error) {
|
||||
bazelPath := filepath.Join(os.Getenv("RUNFILES_DIR"), "com_github_jetstack_cert_manager", "deploy", "charts", "cert-manager", "crds")
|
||||
d, err := os.Stat(bazelPath)
|
||||
if err == os.ErrNotExist {
|
||||
return filepath.Join(filepath.Dir(os.Getenv("GOMOD")), "deploy", "charts", "cert-manager", "crds"), nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if m := d.Mode(); !m.IsDir() {
|
||||
return "", fmt.Errorf("directory containing CRDs is not a directory")
|
||||
}
|
||||
return bazelPath, nil
|
||||
}
|
||||
|
||||
func getPath(name string, path ...string) (string, error) {
|
||||
bazelPath := filepath.Join(append([]string{os.Getenv("RUNFILES_DIR"), "com_github_jetstack_cert_manager"}, path...)...)
|
||||
p, err := exec.LookPath(bazelPath)
|
||||
if err == nil {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
return exec.LookPath(name)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user