Skip to content

Commit a51497f

Browse files
authored
Merge pull request #229 from lichuqiang/e2e
Add e2e test for kubebuilder
2 parents 5d41417 + 80ad8d8 commit a51497f

File tree

7 files changed

+699
-17
lines changed

7 files changed

+699
-17
lines changed

test/e2e/config.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright 2018 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 e2e
18+
19+
import (
20+
"path/filepath"
21+
22+
"github.com/kubernetes-sigs/kubebuilder/test/e2e/framework"
23+
)
24+
25+
// runtime config specified to run e2e tests
26+
type config struct {
27+
domain string
28+
group string
29+
version string
30+
kind string
31+
installName string
32+
namespace string
33+
controllerImageName string
34+
workDir string
35+
}
36+
37+
// initConfig init with a random suffix for test config stuff,
38+
// to avoid conflict when running tests synchronously.
39+
func initConfig(testSuffix string) *config {
40+
testGroup := "bar" + testSuffix
41+
installName := "kube" + testGroup
42+
testNamespace := installName + "-system"
43+
44+
return &config{
45+
domain: "example.com" + testSuffix,
46+
group: testGroup,
47+
version: "v1alpha1",
48+
kind: "Foo" + testSuffix,
49+
installName: installName,
50+
namespace: testNamespace,
51+
controllerImageName: "e2e-test/controller-manager:" + testSuffix,
52+
workDir: filepath.Join(framework.TestContext.ProjectDir, "e2e-"+testSuffix),
53+
}
54+
}
55+
56+
type deploymentTemplateArguments struct {
57+
Namespace string
58+
}
59+
60+
var deploymentTemplate = `
61+
apiVersion: apps/v1beta1
62+
kind: Deployment
63+
metadata:
64+
name: deployment-example
65+
namespace: {{ .Namespace }}
66+
labels:
67+
name: deployment-example
68+
spec:
69+
replicas: 3
70+
selector:
71+
matchLabels:
72+
name: nginx
73+
template:
74+
metadata:
75+
labels:
76+
name: nginx
77+
spec:
78+
containers:
79+
- name: nginx
80+
image: nginx
81+
ports:
82+
- containerPort: 80
83+
`

test/e2e/e2e.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
Copyright 2018 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 e2e
18+
19+
import (
20+
"fmt"
21+
"os"
22+
"path/filepath"
23+
"strings"
24+
"testing"
25+
"time"
26+
27+
"github.com/golang/glog"
28+
"github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/util"
29+
"github.com/kubernetes-sigs/kubebuilder/test/e2e/framework"
30+
"github.com/kubernetes-sigs/kubebuilder/test/e2e/framework/ginkgowrapper"
31+
e2einternal "github.com/kubernetes-sigs/kubebuilder/test/internal/e2e"
32+
. "github.com/onsi/ginkgo"
33+
. "github.com/onsi/gomega"
34+
)
35+
36+
// RunE2ETests checks configuration parameters (specified through flags) and then runs
37+
// E2E tests using the Ginkgo runner.
38+
func RunE2ETests(t *testing.T) {
39+
RegisterFailHandler(ginkgowrapper.Fail)
40+
glog.Infof("Starting kubebuilder suite")
41+
RunSpecs(t, "Kubebuilder e2e suite")
42+
}
43+
44+
var _ = Describe("main workflow", func() {
45+
It("should perform main kubebuilder workflow successfully", func() {
46+
testSuffix := framework.RandomSuffix()
47+
c := initConfig(testSuffix)
48+
kubebuilderTest := e2einternal.NewKubebuilderTest(c.workDir, framework.TestContext.BinariesDir)
49+
50+
prepare(c.workDir)
51+
defer cleanup(kubebuilderTest, c.workDir, c.controllerImageName)
52+
53+
var controllerPodName string
54+
55+
By("init project")
56+
initOptions := []string{"--domain", c.domain}
57+
err := kubebuilderTest.Init(initOptions)
58+
Expect(err).NotTo(HaveOccurred())
59+
60+
By("creating resource definition")
61+
resourceOptions := []string{"--group", c.group, "--version", c.version, "--kind", c.kind}
62+
err = kubebuilderTest.CreateResource(resourceOptions)
63+
Expect(err).NotTo(HaveOccurred())
64+
65+
By("creating core-type resource controller")
66+
controllerOptions := []string{"--group", "apps", "--version", "v1beta2", "--kind", "Deployment", "--core-type"}
67+
err = kubebuilderTest.CreateController(controllerOptions)
68+
Expect(err).NotTo(HaveOccurred())
69+
70+
By("building image")
71+
// The scaffold test cases generated for core types controller cannot work
72+
// without manually modification.
73+
// See https://github.com/kubernetes-sigs/kubebuilder/pull/193 for more details
74+
// Skip the test for core types controller in build process.
75+
testCmdWithoutCoreType := "RUN find ./ -not -path './pkg/controller/deployment/*' -name '*_test.go' -print0 | xargs -0n1 dirname | xargs go test\n"
76+
err = framework.ReplaceFileConent(`RUN go test(.*)\n`, testCmdWithoutCoreType, filepath.Join(c.workDir, "Dockerfile.controller"))
77+
Expect(err).NotTo(HaveOccurred())
78+
79+
imageOptions := []string{"-t", c.controllerImageName}
80+
err = kubebuilderTest.BuildImage(imageOptions)
81+
Expect(err).NotTo(HaveOccurred())
82+
83+
By("creating config")
84+
configOptions := []string{"--controller-image", c.controllerImageName, "--name", c.installName}
85+
err = kubebuilderTest.CreateConfig(configOptions)
86+
Expect(err).NotTo(HaveOccurred())
87+
88+
By("installing controller-manager in cluster")
89+
inputFile := filepath.Join(kubebuilderTest.Dir, "hack", "install.yaml")
90+
installOptions := []string{"apply", "-f", inputFile}
91+
_, err = kubebuilderTest.RunKubectlCommand(framework.GetKubectlArgs(installOptions))
92+
Expect(err).NotTo(HaveOccurred())
93+
94+
By("validate the controller-manager pod running as expected")
95+
verifyContollerUp := func() error {
96+
// Get pod name
97+
// TODO: Use kubectl to format the output with a go-template
98+
getOptions := []string{"get", "pods", "-n", c.namespace, "-l", "control-plane=controller-manager", "-o", "go-template={{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ .metadata.name }}{{ \"\\n\" }}{{ end }}{{ end }}"}
99+
podOutput, err := kubebuilderTest.RunKubectlCommand(framework.GetKubectlArgs(getOptions))
100+
Expect(err).NotTo(HaveOccurred())
101+
// TODO: validate pod replicas if not default to 1
102+
podNames := framework.ParseCmdOutput(podOutput)
103+
if len(podNames) != 1 {
104+
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
105+
}
106+
controllerPodName = podNames[0]
107+
Expect(controllerPodName).Should(HavePrefix(c.installName+"-controller-manager"))
108+
109+
// Validate pod status
110+
getOptions = []string{"get", "pods", controllerPodName, "-n", c.namespace, "-o", "jsonpath={.status.phase}"}
111+
status, err := kubebuilderTest.RunKubectlCommand(framework.GetKubectlArgs(getOptions))
112+
Expect(err).NotTo(HaveOccurred())
113+
if status != "Running" {
114+
return fmt.Errorf("controller pod in %s status", status)
115+
}
116+
117+
return nil
118+
}
119+
Eventually(verifyContollerUp, 1*time.Minute, 500*time.Millisecond).Should(BeNil())
120+
121+
By("creating resource object")
122+
inputFile = filepath.Join(kubebuilderTest.Dir, "hack", "sample", strings.ToLower(c.kind)+".yaml")
123+
createOptions := []string{"create", "-f", inputFile}
124+
_, err = kubebuilderTest.RunKubectlCommand(framework.GetKubectlArgs(createOptions))
125+
Expect(err).NotTo(HaveOccurred())
126+
127+
By("validate the created resource object gets reconciled in controller")
128+
controllerContainerLogs := func() string {
129+
// Check container log to validate that the created resource object gets reconciled in controller
130+
logOptions := []string{"logs", controllerPodName, "-n", c.namespace}
131+
logOutput, err := kubebuilderTest.RunKubectlCommand(framework.GetKubectlArgs(logOptions))
132+
Expect(err).NotTo(HaveOccurred())
133+
134+
return logOutput
135+
}
136+
Eventually(controllerContainerLogs, 1*time.Minute, 500*time.Millisecond).Should(ContainSubstring(fmt.Sprintf("to reconcile %s-example", strings.ToLower(c.kind))))
137+
138+
By("creating other kind of resource object")
139+
inputFile = filepath.Join(kubebuilderTest.Dir, "hack", "sample", "deployment.yaml")
140+
util.WriteIfNotFound(inputFile,
141+
"deployment-template",
142+
deploymentTemplate,
143+
deploymentTemplateArguments{Namespace: c.namespace},
144+
)
145+
createOptions = []string{"create", "-f", inputFile}
146+
_, err = kubebuilderTest.RunKubectlCommand(framework.GetKubectlArgs(createOptions))
147+
Expect(err).NotTo(HaveOccurred())
148+
149+
By("validate other kind of object gets reconciled in controller")
150+
Eventually(controllerContainerLogs, 1*time.Minute, 500*time.Millisecond).Should(ContainSubstring("to reconcile deployment-example"))
151+
})
152+
})
153+
154+
func prepare(workDir string) {
155+
By("create a path under given project dir, as the test work dir")
156+
err := os.MkdirAll(workDir, 0755)
157+
Expect(err).NotTo(HaveOccurred())
158+
}
159+
160+
func cleanup(builderTest *e2einternal.KubebuilderTest, workDir string, imageName string) {
161+
By("clean up created API objects during test process")
162+
inputFile := filepath.Join(workDir, "hack", "install.yaml")
163+
createOptions := []string{"delete", "-f", inputFile}
164+
builderTest.RunKubectlCommand(framework.GetKubectlArgs(createOptions))
165+
166+
By("remove container image created during test")
167+
builderTest.CleanupImage([]string{imageName})
168+
169+
By("remove test work dir")
170+
os.RemoveAll(workDir)
171+
}

test/e2e/e2e_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright 2018 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 e2e
18+
19+
import (
20+
"testing"
21+
22+
"github.com/kubernetes-sigs/kubebuilder/test/e2e/framework"
23+
"github.com/spf13/pflag"
24+
)
25+
26+
func init() {
27+
framework.RegisterFlags()
28+
pflag.Parse()
29+
}
30+
31+
func TestE2E(t *testing.T) {
32+
RunE2ETests(t)
33+
}

0 commit comments

Comments
 (0)