Skip to content

Commit 9df6ce9

Browse files
authored
Remove envtest-existing from upgradecheck (#3158)
* Remove envtest-existing from upgradecheck `envtest-existing` tests have been flaky and we are moving towards KUTTL tests for e2e PostgresCluster behavior; several tests in the `upgradecheck` package were originally written as `envtest-existing` but are not really suitable as KUTTL tests, so this PR changes them from `envtest-existing` to `envtest` Issue [sc-14243]
1 parent 31847c4 commit 9df6ce9

File tree

2 files changed

+175
-124
lines changed

2 files changed

+175
-124
lines changed

internal/upgradecheck/header_test.go

Lines changed: 12 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//go:build envtest
2+
// +build envtest
3+
14
package upgradecheck
25

36
/*
@@ -18,146 +21,32 @@ package upgradecheck
1821
import (
1922
"context"
2023
"encoding/json"
21-
"fmt"
2224
"net/http"
23-
"net/http/httptest"
24-
"os"
2525
"path/filepath"
26-
"strings"
2726
"testing"
2827

29-
"github.com/wojas/genericr"
3028
"gotest.tools/v3/assert"
3129
corev1 "k8s.io/api/core/v1"
32-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33-
"k8s.io/apimachinery/pkg/types"
3430
"k8s.io/apimachinery/pkg/util/uuid"
35-
"k8s.io/apimachinery/pkg/version"
3631
"k8s.io/client-go/discovery"
3732

3833
// Google Kubernetes Engine / Google Cloud Platform authentication provider
3934
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
4035
"k8s.io/client-go/rest"
4136
crclient "sigs.k8s.io/controller-runtime/pkg/client"
42-
"sigs.k8s.io/controller-runtime/pkg/client/fake"
4337
"sigs.k8s.io/controller-runtime/pkg/envtest"
4438

4539
"github.com/crunchydata/postgres-operator/internal/controller/postgrescluster"
4640
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
47-
"github.com/crunchydata/postgres-operator/internal/logging"
4841
"github.com/crunchydata/postgres-operator/internal/naming"
4942
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
5043
)
5144

52-
type fakeClientWithError struct {
53-
crclient.Client
54-
errorType string
55-
}
56-
57-
func (f *fakeClientWithError) Get(ctx context.Context, key types.NamespacedName, obj crclient.Object) error {
58-
switch f.errorType {
59-
case "get error":
60-
return fmt.Errorf("get error")
61-
default:
62-
return f.Client.Get(ctx, key, obj)
63-
}
64-
}
65-
66-
// TODO: PatchType is not supported currently by fake
67-
// - https://github.com/kubernetes/client-go/issues/970
68-
// Once that gets fixed, we can test without envtest
69-
func (f *fakeClientWithError) Patch(ctx context.Context, obj crclient.Object,
70-
patch crclient.Patch, opts ...crclient.PatchOption) error {
71-
switch {
72-
case f.errorType == "patch error":
73-
return fmt.Errorf("patch error")
74-
default:
75-
return f.Client.Patch(ctx, obj, patch, opts...)
76-
}
77-
}
78-
79-
func (f *fakeClientWithError) List(ctx context.Context, objList crclient.ObjectList,
80-
opts ...crclient.ListOption) error {
81-
switch f.errorType {
82-
case "list error":
83-
return fmt.Errorf("list error")
84-
default:
85-
return f.Client.List(ctx, objList, opts...)
86-
}
87-
}
88-
89-
func setupDeploymentID(t *testing.T) string {
90-
t.Helper()
91-
deploymentID = string(uuid.NewUUID())
92-
return deploymentID
93-
}
94-
95-
func setupFakeClientWithPGOScheme(t *testing.T, includeCluster bool) crclient.Client {
96-
t.Helper()
97-
pgoScheme, err := runtime.CreatePostgresOperatorScheme()
98-
if err != nil {
99-
t.Fatal(err)
100-
}
101-
if includeCluster {
102-
pc := &v1beta1.PostgresClusterList{
103-
Items: []v1beta1.PostgresCluster{
104-
{
105-
ObjectMeta: metav1.ObjectMeta{
106-
Name: "hippo",
107-
},
108-
},
109-
{
110-
ObjectMeta: metav1.ObjectMeta{
111-
Name: "elephant",
112-
},
113-
},
114-
},
115-
}
116-
return fake.NewClientBuilder().WithScheme(pgoScheme).WithLists(pc).Build()
117-
}
118-
return fake.NewClientBuilder().WithScheme(pgoScheme).Build()
119-
}
120-
121-
func setupVersionServer(t *testing.T, works bool) (version.Info, *httptest.Server) {
122-
t.Helper()
123-
expect := version.Info{
124-
Major: "1",
125-
Minor: "22",
126-
GitCommit: "v1.22.2",
127-
}
128-
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,
129-
req *http.Request) {
130-
if works {
131-
output, _ := json.Marshal(expect)
132-
w.Header().Set("Content-Type", "application/json")
133-
w.WriteHeader(http.StatusOK)
134-
// We don't need to check the error output from this
135-
_, _ = w.Write(output)
136-
} else {
137-
w.WriteHeader(http.StatusBadRequest)
138-
}
139-
}))
140-
t.Cleanup(server.Close)
141-
142-
return expect, server
143-
}
144-
145-
func setupLogCapture(ctx context.Context) (context.Context, *[]string) {
146-
calls := []string{}
147-
testlog := genericr.New(func(input genericr.Entry) {
148-
calls = append(calls, input.Message)
149-
})
150-
return logging.NewContext(ctx, testlog), &calls
151-
}
152-
15345
func TestGenerateHeader(t *testing.T) {
154-
if !strings.EqualFold(os.Getenv("USE_EXISTING_CLUSTER"), "true") {
155-
t.Skip("Server-Side Apply required")
156-
}
15746
setupDeploymentID(t)
15847
ctx := context.Background()
15948
env := &envtest.Environment{
160-
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")},
49+
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
16150
}
16251
cfg, err := env.Start()
16352
assert.NilError(t, err)
@@ -168,6 +57,8 @@ func TestGenerateHeader(t *testing.T) {
16857
cc, err := crclient.New(cfg, crclient.Options{Scheme: pgoScheme})
16958
assert.NilError(t, err)
17059

60+
setupNamespace(t, cc)
61+
17162
dc, err := discovery.NewDiscoveryClientForConfig(cfg)
17263
assert.NilError(t, err)
17364
server, err := dc.ServerVersion()
@@ -248,9 +139,6 @@ func TestGenerateHeader(t *testing.T) {
248139
}
249140

250141
func TestEnsureID(t *testing.T) {
251-
if !strings.EqualFold(os.Getenv("USE_EXISTING_CLUSTER"), "true") {
252-
t.Skip("Server-Side Apply required")
253-
}
254142
ctx := context.Background()
255143
env := &envtest.Environment{}
256144
config, err := env.Start()
@@ -260,6 +148,8 @@ func TestEnsureID(t *testing.T) {
260148
cc, err := crclient.New(config, crclient.Options{})
261149
assert.NilError(t, err)
262150

151+
setupNamespace(t, cc)
152+
263153
t.Run("success, no id set in mem or configmap", func(t *testing.T) {
264154
deploymentID = ""
265155
oldID := deploymentID
@@ -392,9 +282,6 @@ func TestEnsureID(t *testing.T) {
392282
}
393283

394284
func TestManageUpgradeCheckConfigMap(t *testing.T) {
395-
if !strings.EqualFold(os.Getenv("USE_EXISTING_CLUSTER"), "true") {
396-
t.Skip("Server-Side Apply required")
397-
}
398285
ctx := context.Background()
399286
env := &envtest.Environment{}
400287
config, err := env.Start()
@@ -404,6 +291,8 @@ func TestManageUpgradeCheckConfigMap(t *testing.T) {
404291
cc, err := crclient.New(config, crclient.Options{})
405292
assert.NilError(t, err)
406293

294+
setupNamespace(t, cc)
295+
407296
t.Run("no namespace given", func(t *testing.T) {
408297
ctx, calls := setupLogCapture(ctx)
409298
t.Setenv("PGO_NAMESPACE", "")
@@ -526,9 +415,6 @@ func TestManageUpgradeCheckConfigMap(t *testing.T) {
526415
}
527416

528417
func TestApplyConfigMap(t *testing.T) {
529-
if !strings.EqualFold(os.Getenv("USE_EXISTING_CLUSTER"), "true") {
530-
t.Skip("Server-Side Apply required")
531-
}
532418
ctx := context.Background()
533419
env := &envtest.Environment{}
534420
config, err := env.Start()
@@ -538,6 +424,8 @@ func TestApplyConfigMap(t *testing.T) {
538424
cc, err := crclient.New(config, crclient.Options{})
539425
assert.NilError(t, err)
540426

427+
setupNamespace(t, cc)
428+
541429
t.Run("successful create", func(t *testing.T) {
542430
cmRetrieved := &corev1.ConfigMap{}
543431
err := cc.Get(ctx, naming.AsObjectKey(naming.UpgradeCheckConfigMap()), cmRetrieved)

internal/upgradecheck/helpers_test.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package upgradecheck
2+
3+
/*
4+
Copyright 2021 - 2022 Crunchy Data Solutions, Inc.
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
import (
19+
"context"
20+
"encoding/json"
21+
"fmt"
22+
"net/http"
23+
"net/http/httptest"
24+
"testing"
25+
26+
"github.com/wojas/genericr"
27+
"gotest.tools/v3/assert"
28+
corev1 "k8s.io/api/core/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/apimachinery/pkg/types"
31+
"k8s.io/apimachinery/pkg/util/uuid"
32+
"k8s.io/apimachinery/pkg/version"
33+
crclient "sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
35+
36+
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
37+
"github.com/crunchydata/postgres-operator/internal/logging"
38+
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
39+
)
40+
41+
type fakeClientWithError struct {
42+
crclient.Client
43+
errorType string
44+
}
45+
46+
func (f *fakeClientWithError) Get(ctx context.Context, key types.NamespacedName, obj crclient.Object) error {
47+
switch f.errorType {
48+
case "get error":
49+
return fmt.Errorf("get error")
50+
default:
51+
return f.Client.Get(ctx, key, obj)
52+
}
53+
}
54+
55+
// TODO: PatchType is not supported currently by fake
56+
// - https://github.com/kubernetes/client-go/issues/970
57+
// Once that gets fixed, we can test without envtest
58+
func (f *fakeClientWithError) Patch(ctx context.Context, obj crclient.Object,
59+
patch crclient.Patch, opts ...crclient.PatchOption) error {
60+
switch {
61+
case f.errorType == "patch error":
62+
return fmt.Errorf("patch error")
63+
default:
64+
return f.Client.Patch(ctx, obj, patch, opts...)
65+
}
66+
}
67+
68+
func (f *fakeClientWithError) List(ctx context.Context, objList crclient.ObjectList,
69+
opts ...crclient.ListOption) error {
70+
switch f.errorType {
71+
case "list error":
72+
return fmt.Errorf("list error")
73+
default:
74+
return f.Client.List(ctx, objList, opts...)
75+
}
76+
}
77+
78+
func setupDeploymentID(t *testing.T) string {
79+
t.Helper()
80+
deploymentID = string(uuid.NewUUID())
81+
return deploymentID
82+
}
83+
84+
func setupFakeClientWithPGOScheme(t *testing.T, includeCluster bool) crclient.Client {
85+
t.Helper()
86+
pgoScheme, err := runtime.CreatePostgresOperatorScheme()
87+
if err != nil {
88+
t.Fatal(err)
89+
}
90+
if includeCluster {
91+
pc := &v1beta1.PostgresClusterList{
92+
Items: []v1beta1.PostgresCluster{
93+
{
94+
ObjectMeta: metav1.ObjectMeta{
95+
Name: "hippo",
96+
},
97+
},
98+
{
99+
ObjectMeta: metav1.ObjectMeta{
100+
Name: "elephant",
101+
},
102+
},
103+
},
104+
}
105+
return fake.NewClientBuilder().WithScheme(pgoScheme).WithLists(pc).Build()
106+
}
107+
return fake.NewClientBuilder().WithScheme(pgoScheme).Build()
108+
}
109+
110+
func setupVersionServer(t *testing.T, works bool) (version.Info, *httptest.Server) {
111+
t.Helper()
112+
expect := version.Info{
113+
Major: "1",
114+
Minor: "22",
115+
GitCommit: "v1.22.2",
116+
}
117+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,
118+
req *http.Request) {
119+
if works {
120+
output, _ := json.Marshal(expect)
121+
w.Header().Set("Content-Type", "application/json")
122+
w.WriteHeader(http.StatusOK)
123+
// We don't need to check the error output from this
124+
_, _ = w.Write(output)
125+
} else {
126+
w.WriteHeader(http.StatusBadRequest)
127+
}
128+
}))
129+
t.Cleanup(server.Close)
130+
131+
return expect, server
132+
}
133+
134+
func setupLogCapture(ctx context.Context) (context.Context, *[]string) {
135+
calls := []string{}
136+
testlog := genericr.New(func(input genericr.Entry) {
137+
calls = append(calls, input.Message)
138+
})
139+
return logging.NewContext(ctx, testlog), &calls
140+
}
141+
142+
// setupNamespace creates a namespace that will be deleted by t.Cleanup.
143+
// For upgradechecking, this namespace is set to `postgres-operator`,
144+
// which sometimes is created by other parts of the testing apparatus,
145+
// cf., the createnamespace call in `make check-envtest-existing`.
146+
// When creation fails, it calls t.Fatal. The caller may delete the namespace
147+
// at any time.
148+
func setupNamespace(t testing.TB, cc crclient.Client) {
149+
t.Helper()
150+
ns := &corev1.Namespace{}
151+
ns.Name = "postgres-operator"
152+
ns.Labels = map[string]string{"postgres-operator-test": t.Name()}
153+
154+
ctx := context.Background()
155+
exists := &corev1.Namespace{}
156+
assert.NilError(t, crclient.IgnoreNotFound(
157+
cc.Get(ctx, crclient.ObjectKeyFromObject(ns), exists)))
158+
if exists.Name != "" {
159+
return
160+
}
161+
assert.NilError(t, cc.Create(ctx, ns))
162+
t.Cleanup(func() { assert.Check(t, crclient.IgnoreNotFound(cc.Delete(ctx, ns))) })
163+
}

0 commit comments

Comments
 (0)