Skip to content

Commit f1bc52d

Browse files
authored
Merge pull request #181 from Liujingfang1/memcached
Add test for memcached-api-server project
2 parents 4507935 + ac46db0 commit f1bc52d

20 files changed

+625
-3
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package e2e
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"log"
7+
"os"
8+
"os/exec"
9+
"path/filepath"
10+
"strings"
11+
)
12+
13+
type KubebuilderTest struct {
14+
Dir string
15+
}
16+
17+
func NewKubebuilderTest(dir, binDir string) *KubebuilderTest {
18+
kt := KubebuilderTest{Dir: dir}
19+
os.Setenv("TEST_ASSET_KUBECTL", strings.Join([]string{binDir, "kubectl"}, "/"))
20+
os.Setenv("TEST_ASSET_KUBE_APISERVER", strings.Join([]string{binDir, "kube-apiserver"}, "/"))
21+
os.Setenv("TEST_ASSET_ETCD", strings.Join([]string{binDir, "etcd"}, "/"))
22+
return &kt
23+
}
24+
25+
func (kt *KubebuilderTest) Generate(generateOptions []string) error {
26+
generateOptions = append([]string{"generate"}, generateOptions...)
27+
cmd := exec.Command("kubebuilder", generateOptions...)
28+
return kt.runCommand(cmd)
29+
}
30+
31+
func (kt *KubebuilderTest) Docs(docsOptions []string) error {
32+
docsOptions = append([]string{"docs"}, docsOptions...)
33+
cmd := exec.Command("kubebuilder", docsOptions...)
34+
return kt.runCommand(cmd)
35+
}
36+
37+
func (kt *KubebuilderTest) Build() error {
38+
var errs []string
39+
cmd := exec.Command("go", "build", "./pkg/...")
40+
err := kt.runCommand(cmd)
41+
if err != nil {
42+
errs = append(errs, err.Error())
43+
}
44+
cmd = exec.Command("go", "build", "./cmd/...")
45+
err = kt.runCommand(cmd)
46+
if err != nil {
47+
errs = append(errs, err.Error())
48+
}
49+
if len(errs) > 0 {
50+
return fmt.Errorf(strings.Join(errs, "\n"))
51+
}
52+
return nil
53+
}
54+
55+
func (kt *KubebuilderTest) Test() error {
56+
var errs []string
57+
cmd := exec.Command("go", "test", "./pkg/...")
58+
err := kt.runCommand(cmd)
59+
if err != nil {
60+
errs = append(errs, err.Error())
61+
}
62+
cmd = exec.Command("go", "test", "./cmd/...")
63+
err = kt.runCommand(cmd)
64+
if err != nil {
65+
errs = append(errs, err.Error())
66+
}
67+
if len(errs) > 0 {
68+
return fmt.Errorf(strings.Join(errs, "\n"))
69+
}
70+
return nil
71+
}
72+
73+
func (kt *KubebuilderTest) CreateConfig(configOptions []string) error {
74+
configOptions = append([]string{"create", "config"}, configOptions...)
75+
cmd := exec.Command("kubebuilder", configOptions...)
76+
return kt.runCommand(cmd)
77+
}
78+
79+
func (kt *KubebuilderTest) Diff(pathA, pathB string) error {
80+
cmd := exec.Command("diff", pathA, pathB)
81+
return kt.runCommand(cmd)
82+
}
83+
84+
func (kt *KubebuilderTest) DiffAll(generatedDir, expectedDir string) error {
85+
files, err := ioutil.ReadDir(expectedDir)
86+
if err != nil {
87+
return err
88+
}
89+
var errs []string
90+
for _, f := range files {
91+
generatedFile := filepath.Join(generatedDir, f.Name())
92+
if _, err := os.Stat(generatedFile); err != nil {
93+
errs = append(errs, err.Error())
94+
} else {
95+
err = kt.Diff(generatedFile, filepath.Join(expectedDir, f.Name()))
96+
if err != nil {
97+
errs = append(errs, err.Error())
98+
}
99+
}
100+
}
101+
if len(errs) > 0 {
102+
return fmt.Errorf(strings.Join(errs, "\n"))
103+
}
104+
return nil
105+
}
106+
107+
func (kt *KubebuilderTest) DepEnsure() error {
108+
cmd := exec.Command("dep", "ensure")
109+
return kt.runCommand(cmd)
110+
}
111+
112+
func (kt *KubebuilderTest) VendorUpdate() error {
113+
cmd := exec.Command("kubebuilder", "vendor", "update")
114+
return kt.runCommand(cmd)
115+
}
116+
117+
func (kt *KubebuilderTest) CleanUp() error {
118+
var errs []string
119+
cmd := exec.Command("kubebuilder", "generate", "clean")
120+
err := kt.runCommand(cmd)
121+
if err != nil {
122+
errs = append(errs, err.Error())
123+
}
124+
cmd = exec.Command("rm", "-r", "docs")
125+
err = kt.runCommand(cmd)
126+
if err != nil {
127+
errs = append(errs, err.Error())
128+
}
129+
if len(errs) > 0 {
130+
return fmt.Errorf(strings.Join(errs, "\n"))
131+
}
132+
return nil
133+
}
134+
135+
func (kt *KubebuilderTest) runCommand(cmd *exec.Cmd) error {
136+
cmd.Dir = kt.Dir
137+
cmd.Env = os.Environ()
138+
command := strings.Join(cmd.Args, " ")
139+
output, err := cmd.Output()
140+
if err != nil {
141+
return fmt.Errorf("%s failed with error: %s", command, string(output))
142+
}
143+
log.Printf("%s finished successfully", command)
144+
return nil
145+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package memcached_test
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"runtime"
7+
"testing"
8+
"github.com/kubernetes-sigs/kubebuilder/samples/internal/test/e2e"
9+
)
10+
11+
var kubebuilderTest *e2e.KubebuilderTest
12+
13+
func setup() {
14+
_, filename, _, _ := runtime.Caller(0)
15+
projectDir := filepath.Dir(filename)
16+
kubebuilderBin := "/tmp/kubebuilder/bin"
17+
kubebuilderTest = e2e.NewKubebuilderTest(projectDir, kubebuilderBin)
18+
}
19+
20+
func teardown() {
21+
kubebuilderTest.CleanUp()
22+
}
23+
24+
func TestMain(m *testing.M) {
25+
setup()
26+
code := m.Run()
27+
teardown()
28+
os.Exit(code)
29+
}
30+
31+
func TestGenerateBuildTest(t *testing.T) {
32+
err := kubebuilderTest.Generate([]string{"--skip-rbac-validation"})
33+
if err != nil {
34+
t.Errorf(err.Error())
35+
}
36+
err = kubebuilderTest.Build()
37+
if err != nil {
38+
t.Errorf(err.Error())
39+
}
40+
err = kubebuilderTest.Test()
41+
if err != nil {
42+
t.Errorf(err.Error())
43+
}
44+
}
45+
46+
func TestDocs(t *testing.T) {
47+
docsOptions := []string{"--docs-copyright", "Hello", "--title", "World", "--cleanup=false", "--brodocs=false"}
48+
err := kubebuilderTest.Docs(docsOptions)
49+
if err != nil {
50+
t.Errorf(err.Error())
51+
}
52+
docsDir := filepath.Join(kubebuilderTest.Dir, "docs", "reference")
53+
expectedDocsDir := filepath.Join(kubebuilderTest.Dir, "test", "docs", "reference")
54+
err = kubebuilderTest.DiffAll(docsDir, expectedDocsDir)
55+
if err != nil {
56+
t.Errorf(err.Error())
57+
}
58+
}
59+
60+
func TestCreateConfig(t *testing.T) {
61+
configOptions := []string{"--crds"}
62+
err := kubebuilderTest.CreateConfig(configOptions)
63+
if err != nil {
64+
t.Errorf(err.Error())
65+
}
66+
configFile := filepath.Join(kubebuilderTest.Dir, "hack", "install.yaml")
67+
expectedConfigFile := filepath.Join(kubebuilderTest.Dir, "test", "hack", "install.yaml")
68+
err = kubebuilderTest.Diff(configFile, expectedConfigFile)
69+
if err != nil {
70+
t.Errorf(err.Error())
71+
}
72+
}

samples/memcached-api-server/pkg/controller/memcached/controller.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ func (bc *MemcachedController) updateMemcachedStatus(mc *myappsv1alpha1.Memcache
9393

9494
// +controller:group=myapps,version=v1alpha1,kind=Memcached,resource=memcacheds
9595
// +informers:group=apps,version=v1,kind=Deployment
96-
// +rbac:rbac:groups=apps,resources=Deployment,verbs=get;list;watch;create;update;patch;delete
96+
// +rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
9797
// +informers:group=apps,version=v1,kind=ReplicaSet
98-
// +rbac:rbac:groups=apps,resources=ReplicaSet,verbs=get;list;watch
98+
// +rbac:groups=apps,resources=replicasets,verbs=get;list;watch
9999
// +informers:group=core,version=v1,kind=Pod
100-
// +rbac:rbac:groups="",resources=Pod,verbs=get;list;watch
100+
// +rbac:groups=core,resources=pods,verbs=get;list;watch
101101
type MemcachedController struct {
102102
args.InjectArgs
103103

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
example_location: "examples"
2+
api_groups:
3+
- "Myapps"
4+
resource_categories:
5+
- name: "Myapps"
6+
include: "myapps"
7+
resources:
8+
- name: "Memcached"
9+
version: "v1alpha1"
10+
group: "myapps"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
# <strong>Field Definitions</strong>
3+
4+
------------
5+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## Initializer v1
2+
3+
Group | Version | Kind
4+
------------ | ---------- | -----------
5+
`meta` | `v1` | `Initializer`
6+
7+
8+
9+
Initializer is information about an initializer that has not yet completed.
10+
11+
<aside class="notice">
12+
Appears In:
13+
14+
<ul>
15+
<li><a href="#initializers-v1">Initializers v1</a></li>
16+
</ul></aside>
17+
18+
Field | Description
19+
------------ | -----------
20+
`name`<br /> *string* | name of the process that is responsible for initializing this object.
21+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## Initializers v1
2+
3+
Group | Version | Kind
4+
------------ | ---------- | -----------
5+
`meta` | `v1` | `Initializers`
6+
7+
8+
9+
Initializers tracks the progress of initialization.
10+
11+
<aside class="notice">
12+
Appears In:
13+
14+
<ul>
15+
<li><a href="#objectmeta-v1">ObjectMeta v1</a></li>
16+
</ul></aside>
17+
18+
Field | Description
19+
------------ | -----------
20+
`pending`<br /> *[Initializer](#initializer-v1) array* <br /> **patch type**: *merge* <br /> **patch merge key**: *name* | Pending is a list of initializers that must execute in order before this object is visible. When the last pending initializer is removed, and no failing result is set, the initializers struct will be set to nil and the object is considered as initialized and visible to all clients.
21+
`result`<br /> *[Status](#status-v1)* | If result is set with the Failure field, the object will be persisted to storage and then deleted, ensuring that other clients can observe the deletion.
22+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## ListMeta v1
2+
3+
Group | Version | Kind
4+
------------ | ---------- | -----------
5+
`meta` | `v1` | `ListMeta`
6+
7+
8+
9+
ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.
10+
11+
<aside class="notice">
12+
Appears In:
13+
14+
<ul>
15+
<li><a href="#status-v1">Status v1</a></li>
16+
</ul></aside>
17+
18+
Field | Description
19+
------------ | -----------
20+
`continue`<br /> *string* | continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response.
21+
`resourceVersion`<br /> *string* | String that identifies the server&#39;s internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency
22+
`selfLink`<br /> *string* | selfLink is a URL representing this object. Populated by the system. Read-only.
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
3+
-----------
4+
# Memcached v1alpha1
5+
6+
7+
8+
Group | Version | Kind
9+
------------ | ---------- | -----------
10+
`myapps` | `v1alpha1` | `Memcached`
11+
12+
13+
14+
15+
16+
17+
18+
Memcached
19+
20+
21+
22+
Field | Description
23+
------------ | -----------
24+
`apiVersion`<br /> *string* | APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
25+
`kind`<br /> *string* | Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
26+
`metadata`<br /> *[ObjectMeta](#objectmeta-v1)* |
27+
`spec`<br /> *[MemcachedSpec](#memcachedspec-v1alpha1)* |
28+
`status`<br /> *[MemcachedStatus](#memcachedstatus-v1alpha1)* |
29+
30+
31+
### MemcachedSpec v1alpha1
32+
33+
<aside class="notice">
34+
Appears In:
35+
36+
<ul>
37+
<li><a href="#memcached-v1alpha1">Memcached v1alpha1</a></li>
38+
</ul></aside>
39+
40+
Field | Description
41+
------------ | -----------
42+
`size`<br /> *integer* | INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
43+
44+
### MemcachedStatus v1alpha1
45+
46+
<aside class="notice">
47+
Appears In:
48+
49+
<ul>
50+
<li><a href="#memcached-v1alpha1">Memcached v1alpha1</a></li>
51+
</ul></aside>
52+
53+
Field | Description
54+
------------ | -----------
55+
`nodes`<br /> *string array* | INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
56+
57+
58+
59+
60+

0 commit comments

Comments
 (0)