Skip to content

Commit 00ef545

Browse files
authored
commands/.../test,pkg/test: add --up-local flag to test local (#781)
* commands/.../test,pkg/test: add --up-local flag to test local
1 parent 07ed6d2 commit 00ef545

File tree

18 files changed

+612
-39
lines changed

18 files changed

+612
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
### Added
99

1010
- A new command [`operator-sdk print-deps`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#print-deps) which prints Golang packages and versions expected by the current Operator SDK version. Supplying `--as-file` prints packages and versions in Gopkg.toml format. ([#772](https://github.com/operator-framework/operator-sdk/pull/772))
11+
- Add [`up-local`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#flags-9) flag to `test local` subcommand ([#781](https://github.com/operator-framework/operator-sdk/pull/781))
1112
- Add [`no-setup`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#flags-9) flag to `test local` subcommand ([#770](https://github.com/operator-framework/operator-sdk/pull/770))
1213
- Add [`image`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#flags-9) flag to `test local` subcommand ([#768](https://github.com/operator-framework/operator-sdk/pull/768))
1314
- Ansible Operator log output includes much more information for troubleshooting ansible errors. ([#713](https://github.com/operator-framework/operator-sdk/pull/713))

Gopkg.lock

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

commands/operator-sdk/cmd/test/local.go

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type testLocalConfig struct {
4545
namespacedManPath string
4646
goTestFlags string
4747
namespace string
48+
upLocal bool
4849
noSetup bool
4950
image string
5051
}
@@ -62,6 +63,7 @@ func NewTestLocalCmd() *cobra.Command {
6263
testCmd.Flags().StringVar(&tlConfig.namespacedManPath, "namespaced-manifest", "", "Path to manifest for per-test, namespaced resources (e.g. RBAC and Operator manifest)")
6364
testCmd.Flags().StringVar(&tlConfig.goTestFlags, "go-test-flags", "", "Additional flags to pass to go test")
6465
testCmd.Flags().StringVar(&tlConfig.namespace, "namespace", "", "If non-empty, single namespace to run tests in")
66+
testCmd.Flags().BoolVar(&tlConfig.upLocal, "up-local", false, "Enable running operator locally with go run instead of as an image in the cluster")
6567
testCmd.Flags().BoolVar(&tlConfig.noSetup, "no-setup", false, "Disable test resource creation")
6668
testCmd.Flags().StringVar(&tlConfig.image, "image", "", "Use a different operator image from the one specified in the namespaced manifest")
6769

@@ -76,6 +78,10 @@ func testLocalFunc(cmd *cobra.Command, args []string) {
7678
log.Fatal("the global-manifest and namespaced-manifest flags cannot be enabled at the same time as the no-setup flag")
7779
}
7880

81+
if tlConfig.upLocal && tlConfig.namespace == "" {
82+
log.Fatal("must specify a namespace to run in when -up-local flag is set")
83+
}
84+
7985
log.Info("Testing operator locally.")
8086

8187
// if no namespaced manifest path is given, combine deploy/service_account.yaml, deploy/role.yaml, deploy/role_binding.yaml and deploy/operator.yaml
@@ -85,28 +91,29 @@ func testLocalFunc(cmd *cobra.Command, args []string) {
8591
log.Fatalf("could not create %s: (%v)", deployTestDir, err)
8692
}
8793
tlConfig.namespacedManPath = filepath.Join(deployTestDir, "namespace-manifests.yaml")
88-
89-
sa, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.ServiceAccountYamlFile))
90-
if err != nil {
91-
log.Warnf("could not find the serviceaccount manifest: (%v)", err)
92-
}
93-
role, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.RoleYamlFile))
94-
if err != nil {
95-
log.Warnf("could not find role manifest: (%v)", err)
96-
}
97-
roleBinding, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.RoleBindingYamlFile))
98-
if err != nil {
99-
log.Warnf("could not find role_binding manifest: (%v)", err)
100-
}
101-
operator, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.OperatorYamlFile))
102-
if err != nil {
103-
log.Fatalf("could not find operator manifest: (%v)", err)
104-
}
10594
combined := []byte{}
106-
combined = combineManifests(combined, sa)
107-
combined = combineManifests(combined, role)
108-
combined = combineManifests(combined, roleBinding)
109-
combined = append(combined, operator...)
95+
if !tlConfig.upLocal {
96+
sa, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.ServiceAccountYamlFile))
97+
if err != nil {
98+
log.Warnf("could not find the serviceaccount manifest: (%v)", err)
99+
}
100+
role, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.RoleYamlFile))
101+
if err != nil {
102+
log.Warnf("could not find role manifest: (%v)", err)
103+
}
104+
roleBinding, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.RoleBindingYamlFile))
105+
if err != nil {
106+
log.Warnf("could not find role_binding manifest: (%v)", err)
107+
}
108+
operator, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.OperatorYamlFile))
109+
if err != nil {
110+
log.Fatalf("could not find operator manifest: (%v)", err)
111+
}
112+
combined = combineManifests(combined, sa)
113+
combined = combineManifests(combined, role)
114+
combined = combineManifests(combined, roleBinding)
115+
combined = append(combined, operator...)
116+
}
110117
err = ioutil.WriteFile(tlConfig.namespacedManPath, combined, os.FileMode(fileutil.DefaultFileMode))
111118
if err != nil {
112119
log.Fatalf("could not create temporary namespaced manifest file: (%v)", err)
@@ -191,6 +198,9 @@ func testLocalFunc(cmd *cobra.Command, args []string) {
191198
if tlConfig.namespace != "" || tlConfig.noSetup {
192199
testArgs = append(testArgs, "-"+test.SingleNamespaceFlag, "-parallel=1")
193200
}
201+
if tlConfig.upLocal {
202+
testArgs = append(testArgs, "-"+test.LocalOperatorFlag)
203+
}
194204
dc := exec.Command("go", testArgs...)
195205
dc.Env = append(os.Environ(), fmt.Sprintf("%v=%v", test.TestNamespaceEnv, tlConfig.namespace))
196206
dc.Dir = projutil.MustGetwd()

doc/sdk-cli-reference.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ Runs the tests locally
276276
* `--namespaced-manifest` string - path to manifest for per-test, namespaced resources (default: combines deploy/service_account.yaml, deploy/rbac.yaml, and deploy/operator.yaml)
277277
* `--namespace` string - if non-empty, single namespace to run tests in (e.g. "operator-test") (default: "")
278278
* `--go-test-flags` string - extra arguments to pass to `go test` (e.g. -f "-v -parallel=2")
279-
* `--no-setup` bool - disable test resource creation
279+
* `--up-local` - enable running operator locally with go run instead of as an image in the cluster
280+
* `--no-setup` - disable test resource creation
280281
* `--image` string - use a different operator image from the one specified in the namespaced manifest
281282
* `-h, --help` - help for local
282283

doc/test-framework/writing-e2e-tests.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,9 @@ in your namespaced manifest. The custom `Create` function use the controller-run
121121
creates a cleanup function that is called by `ctx.Cleanup` which deletes the resource and then waits for the resource to be
122122
fully deleted before returning. This is configurable with `CleanupOptions`. For info on how to use `CleanupOptions` see
123123
[this section](#how-to-use-cleanup).
124-
125124

126125
If you want to make sure the operator's deployment is fully ready before moving onto the next part of the
127-
test, the `WaitForDeployment` function from [e2eutil][e2eutil-link] (in the sdk under `pkg/test/e2eutil`) can be used:
126+
test, the `WaitForOperatorDeployment` function from [e2eutil][e2eutil-link] (in the sdk under `pkg/test/e2eutil`) can be used:
128127

129128
```go
130129
// get namespace
@@ -135,7 +134,7 @@ if err != nil {
135134
// get global framework variables
136135
f := framework.Global
137136
// wait for memcached-operator to be ready
138-
err = e2eutil.WaitForDeployment(t, f.KubeClient, namespace, "memcached-operator", 1, time.Second*5, time.Second*30)
137+
err = e2eutil.WaitForOperatorDeployment(t, f.KubeClient, namespace, "memcached-operator", 1, time.Second*5, time.Second*30)
139138
if err != nil {
140139
t.Fatal(err)
141140
}
@@ -188,7 +187,10 @@ if err != nil {
188187
```
189188

190189
Now we can check if the operator successfully worked. In the case of the memcached operator, it should have
191-
created a deployment called "example-memcached" with 3 replicas:
190+
created a deployment called "example-memcached" with 3 replicas. To check, we use the `WaitForDeployment` function, which
191+
is the same as `WaitForOperatorDeployment` with the exception that `WaitForOperatorDeployment` will skip waiting
192+
for the deployment if the test is run locally and the `--up-local` flag is set; the `WaitForDeployment` function always
193+
waits for the deployment:
192194

193195
```go
194196
// wait for example-memcached to reach 3 replicas
@@ -228,28 +230,48 @@ default test settings, such as locations of your global resource manifest file (
228230
`deploy/crd.yaml`) and your namespaced resource manifest file (by default `deploy/service_account.yaml` concatenated with
229231
`deploy/rbac.yaml` and `deploy/operator.yaml`), and allows the user to configure runtime options. There are 2 ways to use the
230232
subcommand: local and cluster.
233+
231234
### Local
235+
232236
To run the tests locally, run the `operator-sdk test local` command in your project root and pass the location of the tests
233237
as an argument. You can use `--help` to view the other configuration options and use `--go-test-flags` to pass in arguments to `go test`. Here is an example command:
234238

235239
```shell
236240
$ operator-sdk test local ./test/e2e --go-test-flags "-v -parallel=2"
237241
```
238242

243+
#### Image Flag
244+
239245
If you wish to specify a different operator image than specified in your `operator.yaml` file (or a user-specified
240246
namespaced manifest file), you can use the `--image` flag:
241247

242248
```shell
243249
$ operator-sdk test local ./test/e2e --image quay.io/example/my-operator:v0.0.2
244250
```
245251

252+
#### Namespace Flag
253+
246254
If you wish to run all the tests in 1 namespace (which also forces `-parallel=1`), you can use the `--namespace` flag:
247255

248256
```shell
249257
$ kubectl create namespace operator-test
250258
$ operator-sdk test local ./test/e2e --namespace operator-test
251259
```
252260

261+
#### Up-Local Flag
262+
263+
To run the operator itself locally during the tests instead of starting a deployment in the cluster, you can use the
264+
`--up-local` flag. This mode will still create global resources, but by default will not create any in-cluster namespaced
265+
resources unless the user specifies one through the `--namespaced-manifest` flag. (Note: the `--up-local` flag requires
266+
the `--namespace` flag):
267+
268+
```shell
269+
$ kubectl create namespace operator-test
270+
$ operator-sdk test local ./test/e2e --namespace operator-test --up-local
271+
```
272+
273+
#### No-Setup Flag
274+
253275
If you would prefer to create the resources yourself and skip resource creation, you can use the `--no-setup` flag:
254276
```shell
255277
$ kubectl create namespace operator-test
@@ -263,6 +285,8 @@ $ operator-sdk test local ./test/e2e --namespace operator-test --no-setup
263285

264286
For more documentation on the `operator-sdk test local` command, see the [SDK CLI Reference][sdk-cli-ref] doc.
265287

288+
#### Running Go Test Directly (Not Recommended)
289+
266290
For advanced use cases, it is possible to run the tests via `go test` directly. As long as all flags defined
267291
in [MainEntry][main-entry-link] are declared, the tests will run correctly. Running the tests directly with missing flags
268292
will result in undefined behavior. This is an example `go test` equivalent to the `operator-sdk test local` example above:

hack/tests/test-subcommand.sh

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@ set -ex
55

66
pushd test/test-framework
77
# test framework with defaults
8-
operator-sdk test local .
8+
operator-sdk test local ./test/e2e
9+
910
# test operator-sdk test flags
10-
operator-sdk test local . --global-manifest deploy/crds/cache_v1alpha1_memcached_crd.yaml --namespaced-manifest deploy/namespace-init.yaml --go-test-flags "-parallel 1" --kubeconfig $HOME/.kube/config --image=quay.io/coreos/operator-sdk-dev:test-framework-operator-runtime
11-
# test operator-sdk test local single namespace mode
12-
kubectl create namespace test-memcached
11+
operator-sdk test local ./test/e2e --global-manifest deploy/crds/cache_v1alpha1_memcached_crd.yaml --namespaced-manifest deploy/namespace-init.yaml --go-test-flags "-parallel 1" --kubeconfig $HOME/.kube/config --image=quay.io/coreos/operator-sdk-dev:test-framework-operator-runtime
12+
1313
# we use the test-memcached namespace for all future tests, so we only need to set this trap once
14+
kubectl create namespace test-memcached
1415
trap_add 'kubectl delete namespace test-memcached || true' EXIT
15-
operator-sdk test local . --namespace=test-memcached
16+
operator-sdk test local ./test/e2e --namespace=test-memcached
1617
kubectl delete namespace test-memcached
18+
19+
# test operator in up local mode
20+
kubectl create namespace test-memcached
21+
operator-sdk test local ./test/e2e --up-local --namespace=test-memcached
22+
kubectl delete namespace test-memcached
23+
1724
# test operator in no-setup mode
1825
kubectl create namespace test-memcached
1926
kubectl create -f deploy/crds/cache_v1alpha1_memcached_crd.yaml
@@ -23,6 +30,6 @@ kubectl create -f deploy/service_account.yaml --namespace test-memcached
2330
kubectl create -f deploy/role.yaml --namespace test-memcached
2431
kubectl create -f deploy/role_binding.yaml --namespace test-memcached
2532
kubectl create -f deploy/operator.yaml --namespace test-memcached
26-
operator-sdk test local . --namespace=test-memcached --no-setup
33+
operator-sdk test local ./test/e2e --namespace=test-memcached --no-setup
2734
kubectl delete namespace test-memcached
2835
popd

pkg/scaffold/test_pod_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@ import (
1818
"testing"
1919

2020
"github.com/operator-framework/operator-sdk/pkg/scaffold/internal/testutil"
21-
"github.com/operator-framework/operator-sdk/pkg/test"
2221
)
2322

2423
func TestPodTest(t *testing.T) {
2524
s, buf := setupScaffoldAndWriter()
2625
err := s.Execute(appConfig,
2726
&TestPod{
2827
Image: "quay.io/app/operator:v1.0.0",
29-
TestNamespaceEnv: test.TestNamespaceEnv,
28+
TestNamespaceEnv: "TEST_NAMESPACE",
3029
})
3130
if err != nil {
3231
t.Fatalf("failed to execute the scaffold: (%v)", err)

0 commit comments

Comments
 (0)