Skip to content

Commit a5c5dd9

Browse files
committed
add e2e to cover main workflow
1 parent 8cf21a0 commit a5c5dd9

File tree

3 files changed

+315
-0
lines changed

3 files changed

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

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)