Skip to content

Commit a43f866

Browse files
authored
Merge pull request #679 from droot/feature/test-scaffolding-2.0
Moved to ginkgo based tests in scaffolding 2.0
2 parents 76a9cdd + ed46300 commit a43f866

21 files changed

+1063
-38
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ install: build
2929
cp ./bin/kubebuilder $(shell go env GOPATH)/bin/kubebuilder
3030

3131
generate:
32-
./generated_golden.sh
32+
GO111MODULE=on ./generated_golden.sh
3333

3434
test:
3535
go test -v ./cmd/... ./pkg/...

pkg/scaffold/api.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ func (api *API) scaffoldV2() error {
153153
Path: filepath.Join("api", r.Version, fmt.Sprintf("%s_types.go", strings.ToLower(r.Kind))),
154154
},
155155
Resource: r},
156+
&resourcev2.VersionSuiteTest{Resource: r},
157+
&resourcev2.TypesTest{Resource: r},
156158
&resourcev2.Group{Resource: r},
157159
&resourcev2.CRDSample{Resource: r},
158160
&crdv2.EnableWebhookPatch{Resource: r},
@@ -187,8 +189,10 @@ func (api *API) scaffoldV2() error {
187189
fmt.Println(filepath.Join("controllers", fmt.Sprintf("%s_controller.go", strings.ToLower(r.Kind))))
188190

189191
ctrlScaffolder := &resourcev2.Controller{Resource: r}
192+
testsuiteScaffolder := &resourcev2.ControllerSuiteTest{Resource: r}
190193
err := (&Scaffold{}).Execute(
191194
input.Options{},
195+
testsuiteScaffolder,
192196
ctrlScaffolder,
193197
)
194198
if err != nil {
@@ -199,6 +203,11 @@ func (api *API) scaffoldV2() error {
199203
if err != nil {
200204
return fmt.Errorf("error updating main.go with reconciler code: %v", err)
201205
}
206+
207+
err = testsuiteScaffolder.UpdateTestSuite()
208+
if err != nil {
209+
return fmt.Errorf("error updating suite_test.go under controllers pkg: %v", err)
210+
}
202211
}
203212

204213
return nil
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v2
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
"strings"
23+
24+
"github.com/markbates/inflect"
25+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
26+
"sigs.k8s.io/kubebuilder/pkg/scaffold/v1/resource"
27+
"sigs.k8s.io/kubebuilder/pkg/scaffold/v2/internal"
28+
)
29+
30+
var _ input.File = &ControllerSuiteTest{}
31+
32+
// ControllerSuiteTest scaffolds the suite_test.go file to setup the controller test
33+
type ControllerSuiteTest struct {
34+
input.Input
35+
36+
// Resource is the resource to scaffold the controller_kind_test.go file for
37+
Resource *resource.Resource
38+
39+
// ResourcePackage is the package of the Resource
40+
ResourcePackage string
41+
42+
// Plural is the plural lowercase of kind
43+
Plural string
44+
45+
// Is the Group + "." + Domain for the Resource
46+
GroupDomain string
47+
}
48+
49+
// GetInput implements input.File
50+
func (v *ControllerSuiteTest) GetInput() (input.Input, error) {
51+
if v.Path == "" {
52+
v.Path = filepath.Join("controllers", "suite_test.go")
53+
}
54+
v.TemplateBody = controllerSuiteTestTemplate
55+
return v.Input, nil
56+
}
57+
58+
// Validate validates the values
59+
func (v *ControllerSuiteTest) Validate() error {
60+
return v.Resource.Validate()
61+
}
62+
63+
var controllerSuiteTestTemplate = `{{ .Boilerplate }}
64+
65+
package controllers
66+
67+
import (
68+
"path/filepath"
69+
"testing"
70+
71+
. "github.com/onsi/ginkgo"
72+
. "github.com/onsi/gomega"
73+
74+
"k8s.io/client-go/kubernetes/scheme"
75+
"k8s.io/client-go/rest"
76+
"sigs.k8s.io/controller-runtime/pkg/client"
77+
"sigs.k8s.io/controller-runtime/pkg/envtest"
78+
logf "sigs.k8s.io/controller-runtime/pkg/log"
79+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
80+
81+
// +kubebuilder:scaffold:imports
82+
)
83+
84+
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
85+
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
86+
87+
var cfg *rest.Config
88+
var k8sClient client.Client
89+
var testEnv *envtest.Environment
90+
91+
func TestAPIs(t *testing.T) {
92+
RegisterFailHandler(Fail)
93+
94+
RunSpecsWithDefaultAndCustomReporters(t,
95+
"Controller Suite",
96+
[]Reporter{envtest.NewlineReporter{}})
97+
}
98+
99+
var _ = BeforeSuite(func(done Done) {
100+
logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
101+
102+
By("bootstrapping test environment")
103+
testEnv = &envtest.Environment{
104+
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
105+
}
106+
107+
cfg, err := testEnv.Start()
108+
Expect(err).ToNot(HaveOccurred())
109+
Expect(cfg).ToNot(BeNil())
110+
111+
// +kubebuilder:scaffold:scheme
112+
113+
114+
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
115+
Expect(err).ToNot(HaveOccurred())
116+
Expect(k8sClient).ToNot(BeNil())
117+
118+
close(done)
119+
}, 60)
120+
121+
var _ = AfterSuite(func() {
122+
By("tearing down the test environment")
123+
err := testEnv.Stop()
124+
Expect(err).ToNot(HaveOccurred())
125+
})
126+
`
127+
128+
// UpdateTestSuite updates given file (suite_test.go) with code fragments required for
129+
// adding import paths and code setup for new types.
130+
func (a *ControllerSuiteTest) UpdateTestSuite() error {
131+
132+
a.ResourcePackage, a.GroupDomain = getResourceInfo(a.Resource, a.Input)
133+
if a.Plural == "" {
134+
rs := inflect.NewDefaultRuleset()
135+
a.Plural = rs.Pluralize(strings.ToLower(a.Resource.Kind))
136+
}
137+
138+
apiImportCodeFragment := fmt.Sprintf(`"%s/controllers"
139+
%s%s "%s/%s"
140+
`, a.Repo, a.Resource.Group, a.Resource.Version, a.ResourcePackage, a.Resource.Version)
141+
142+
addschemeCodeFragment := fmt.Sprintf(`err = %s%s.AddToScheme(scheme.Scheme)
143+
Expect(err).NotTo(HaveOccurred())
144+
145+
`, a.Resource.Group, a.Resource.Version)
146+
147+
err := internal.InsertStringsInFile(a.Path,
148+
apiPkgImportScaffoldMarker, apiImportCodeFragment,
149+
apiSchemeScaffoldMarker, addschemeCodeFragment)
150+
if err != nil {
151+
return err
152+
}
153+
154+
return nil
155+
}

pkg/scaffold/v2/gomod.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ module {{ .Repo }}
4343
go 1.12
4444
4545
require (
46-
sigs.k8s.io/controller-runtime feature/modules
46+
sigs.k8s.io/controller-runtime v0.2.0-alpha.1
4747
)
4848
`

pkg/scaffold/v2/makefile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ docker-push:
101101
# download controller-gen if necessary
102102
controller-gen:
103103
ifeq (, $(shell which controller-gen))
104-
go get sigs.k8s.io/controller-tools/cmd/[email protected].1
104+
go get sigs.k8s.io/controller-tools/cmd/[email protected].2
105105
CONTROLLER_GEN=$(shell go env GOPATH)/bin/controller-gen
106106
else
107107
CONTROLLER_GEN=$(shell which controller-gen)

pkg/scaffold/v2/typestest.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package v2
17+
18+
import (
19+
"fmt"
20+
"path/filepath"
21+
"strings"
22+
23+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
24+
"sigs.k8s.io/kubebuilder/pkg/scaffold/v1/resource"
25+
)
26+
27+
var _ input.File = &TypesTest{}
28+
29+
// TypesTest scaffolds the api/version/kind_types_test.go file to test the API schema
30+
type TypesTest struct {
31+
input.Input
32+
33+
// Resource is the resource to scaffold the types_test.go file for
34+
Resource *resource.Resource
35+
}
36+
37+
// GetInput implements input.File
38+
func (t *TypesTest) GetInput() (input.Input, error) {
39+
if t.Path == "" {
40+
t.Path = filepath.Join("api", t.Resource.Version,
41+
fmt.Sprintf("%s_types_test.go", strings.ToLower(t.Resource.Kind)))
42+
}
43+
t.TemplateBody = typesTestTemplate
44+
t.IfExistsAction = input.Error
45+
return t.Input, nil
46+
}
47+
48+
// Validate validates the values
49+
func (t *TypesTest) Validate() error {
50+
return t.Resource.Validate()
51+
}
52+
53+
var typesTestTemplate = `{{ .Boilerplate }}
54+
55+
package {{ .Resource.Version }}
56+
57+
import (
58+
"testing"
59+
60+
. "github.com/onsi/ginkgo"
61+
. "github.com/onsi/gomega"
62+
63+
"golang.org/x/net/context"
64+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
65+
"k8s.io/apimachinery/pkg/types"
66+
)
67+
68+
// These tests are written in BDD-style using Ginkgo framework. Refer to
69+
// http://onsi.github.io/ginkgo to learn more.
70+
71+
72+
var _ = Describe("{{ .Resource.Kind }}", func() {
73+
var (
74+
key types.NamespacedName
75+
created, fetched *{{.Resource.Kind}}
76+
)
77+
78+
BeforeEach(func(){
79+
// Add any setup steps that needs to be executed before each test
80+
})
81+
82+
AfterEach(func(){
83+
// Add any teardown steps that needs to be executed after each test
84+
})
85+
86+
// Add Tests for OpenAPI validation (or additonal CRD features) specified in
87+
// your API definition.
88+
// Avoid adding tests for vanilla CRUD operations because they would
89+
// test Kubernetes API server, which isn't the goal here.
90+
Context("Create API", func() {
91+
92+
It("should create an object successfully", func() {
93+
94+
key = types.NamespacedName{
95+
Name: "foo",
96+
{{ if .Resource.Namespaced -}}
97+
Namespace: "default",
98+
{{ end -}}
99+
}
100+
created = &{{ .Resource.Kind }}{
101+
ObjectMeta: metav1.ObjectMeta{
102+
Name: "foo",
103+
{{ if .Resource.Namespaced -}}
104+
Namespace: "default",
105+
{{ end -}}
106+
}}
107+
108+
By("creating an API obj")
109+
Expect(k8sClient.Create(context.TODO(), created)).To(Succeed())
110+
111+
fetched = &{{ .Resource.Kind }}{}
112+
Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed())
113+
Expect(fetched).To(Equal(created))
114+
115+
By("deleting the created object")
116+
Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed())
117+
Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed())
118+
})
119+
120+
})
121+
122+
})
123+
`

0 commit comments

Comments
 (0)