Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit c961770

Browse files
author
Craig Furman
authored
appliance: golden/snapshot testing (#62034)
* appliance: golden/snapshot testing Use envtest (https://book.kubebuilder.io/reference/envtest.html) to start a real Kubernetes API server, backed by a real etcd instance, in tests. The only controller running is our appliance controller, so these tests assert on the changes our controller actually makes to Kubernetes API objects in response to some input, but don't depend on complex infrastruture like container runtimes or persistent volume controllers (since no such controllers are actually running, unlike in a useful Kubernetes cluster). This commit adds a test harness to the appliance package: * It starts the k8s API server only once, not once per test, as this is a relatively slow operation. * Helper functions to run each test in a unique namespace to avoid inter-test dependency. This opens the door to parallelism, but note that testify/suite doesn't currently support parallel tests. * Helper functions to load input ConfigMaps from fixture files. * Passing `-args appliance-update-golden-files` to `go test` will cause checked-in golden files to be updated.
1 parent b6d4a0d commit c961770

23 files changed

+944
-80
lines changed

deps.bzl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,8 @@ def go_dependencies():
643643
name = "com_github_bazelbuild_rules_go",
644644
build_file_proto_mode = "disable_global",
645645
importpath = "github.com/bazelbuild/rules_go",
646-
sum = "h1:uJStI9o5obVWSwquy9WxKNWfZxf2sKA2rpEsX6x5RVM=",
647-
version = "v0.44.0",
646+
sum = "h1:TTl2buKt0lqJe5s6up5FtaB1F95Wg997Lv15MWetU88=",
647+
version = "v0.47.0",
648648
)
649649
go_repository(
650650
name = "com_github_becheran_wildmatch_go",
@@ -2398,8 +2398,8 @@ def go_dependencies():
23982398
name = "com_github_golang_mock",
23992399
build_file_proto_mode = "disable_global",
24002400
importpath = "github.com/golang/mock",
2401-
sum = "h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=",
2402-
version = "v1.6.0",
2401+
sum = "h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=",
2402+
version = "v1.7.0-rc.1",
24032403
)
24042404
go_repository(
24052405
name = "com_github_golang_protobuf",

dev/tool_deps.bzl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file"
44

55
DOCSITE_VERSION = "1.9.4"
66
SRC_CLI_VERSION = "5.3.0"
7+
KUBEBUILDER_ASSETS_VERSION = "1.28.0"
78
CTAGS_VERSION = "6.0.0.2783f009"
89
PACKER_VERSION = "1.8.3"
910
P4_FUSION_VERSION = "v1.13.2-sg.04a293a"
@@ -26,6 +27,14 @@ filegroup(
2627
)
2728
"""
2829

30+
KUBEBUILDER_ASSETS_BUILDFILE = """
31+
filegroup(
32+
name = "kubebuilder-assets",
33+
srcs = glob(["*"]),
34+
visibility = ["//visibility:public"],
35+
)
36+
"""
37+
2938
GCLOUD_VERSION = "456.0.0"
3039
GCLOUD_BUILDFILE = """
3140
package(default_visibility = ["//visibility:public"])
@@ -102,6 +111,31 @@ def tool_deps():
102111
url = "https://github.com/sourcegraph/src-cli/releases/download/{0}/src-cli_{0}_darwin_arm64.tar.gz".format(SRC_CLI_VERSION),
103112
)
104113

114+
# Needed for internal/appliance tests
115+
http_archive(
116+
name = "kubebuilder-assets-darwin-arm64",
117+
build_file_content = KUBEBUILDER_ASSETS_BUILDFILE,
118+
sha256 = "c87c6b3c0aec4233e68a12dc9690bcbe2f8d6cd72c23e670602b17b2d7118325",
119+
urls = ["https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-{}-darwin-arm64.tar.gz".format(KUBEBUILDER_ASSETS_VERSION)],
120+
strip_prefix = "kubebuilder/bin",
121+
)
122+
123+
http_archive(
124+
name = "kubebuilder-assets-darwin-amd64",
125+
build_file_content = KUBEBUILDER_ASSETS_BUILDFILE,
126+
sha256 = "a02e33a3981712c8d2702520f95357bd6c7d03d24b83a4f8ac1c89a9ba4d78c1",
127+
urls = ["https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-{}-darwin-amd64.tar.gz".format(KUBEBUILDER_ASSETS_VERSION)],
128+
strip_prefix = "kubebuilder/bin",
129+
)
130+
131+
http_archive(
132+
name = "kubebuilder-assets-linux-amd64",
133+
build_file_content = KUBEBUILDER_ASSETS_BUILDFILE,
134+
sha256 = "8c816871604cbe119ca9dd8072b576552ae369b96eebc3cdaaf50edd7e3c0c7b",
135+
urls = ["https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-{}-linux-amd64.tar.gz".format(KUBEBUILDER_ASSETS_VERSION)],
136+
strip_prefix = "kubebuilder/bin",
137+
)
138+
105139
# universal-ctags
106140
#
107141
# Two step process to update these. First land a commit in main updating

dev/tools/BUILD.bazel

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,13 @@ sh_binary(
107107
}),
108108
visibility = ["//visibility:public"],
109109
)
110+
111+
alias(
112+
name = "kubebuilder-assets",
113+
actual = select({
114+
"@bazel_tools//src/conditions:darwin_x86_64": "@kubebuilder-assets-darwin-amd64//:kubebuilder-assets",
115+
"@bazel_tools//src/conditions:darwin_arm64": "@kubebuilder-assets-darwin-arm64//:kubebuilder-assets",
116+
"@bazel_tools//src/conditions:linux_x86_64": "@kubebuilder-assets-linux-amd64//:kubebuilder-assets",
117+
}),
118+
visibility = ["//visibility:public"],
119+
)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ require (
252252
github.com/aws/constructs-go/constructs/v10 v10.2.69
253253
github.com/aws/jsii-runtime-go v1.84.0
254254
github.com/bazelbuild/bazel-gazelle v0.35.0
255+
github.com/bazelbuild/rules_go v0.47.0
255256
github.com/derision-test/go-mockgen/v2 v2.0.1
256257
github.com/dghubble/gologin/v2 v2.4.0
257258
github.com/edsrzf/mmap-go v1.1.0

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ github.com/bazelbuild/bazel-gazelle v0.35.0 h1:Bvg+zEHWYwWrhJT4WxyvcU3y1DEJpT/Xl
298298
github.com/bazelbuild/bazel-gazelle v0.35.0/go.mod h1:o2+s90f3w3U6jjw0gcdok0EJOfNK0AK/9RyVP7QkRDk=
299299
github.com/bazelbuild/buildtools v0.0.0-20231115204819-d4c9dccdfbb1 h1:2Gc2Q6hVR1SJ8bBI9Ybzoggp8u/ED2WkM4MfvEIn9+c=
300300
github.com/bazelbuild/buildtools v0.0.0-20231115204819-d4c9dccdfbb1/go.mod h1:689QdV3hBP7Vo9dJMmzhoYIyo/9iMhEmHkJcnaPRCbo=
301-
github.com/bazelbuild/rules_go v0.44.0 h1:uJStI9o5obVWSwquy9WxKNWfZxf2sKA2rpEsX6x5RVM=
302-
github.com/bazelbuild/rules_go v0.44.0/go.mod h1:z7Y8GZ90V4mwgYizbNbEQKmOmx93Q3Btcel4vX7pXoc=
301+
github.com/bazelbuild/rules_go v0.47.0 h1:TTl2buKt0lqJe5s6up5FtaB1F95Wg997Lv15MWetU88=
302+
github.com/bazelbuild/rules_go v0.47.0/go.mod h1:Dhcz716Kqg1RHNWos+N6MlXNkjNP2EwZQ0LukRKJfMs=
303303
github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA=
304304
github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4=
305305
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
@@ -847,8 +847,8 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
847847
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
848848
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
849849
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
850-
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
851-
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
850+
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
851+
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
852852
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
853853
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
854854
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

internal/appliance/BUILD.bazel

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,40 @@ go_library(
3737
],
3838
)
3939

40+
filegroup(
41+
name = "testdata",
42+
srcs = glob(["testdata/**"]),
43+
)
44+
4045
go_test(
4146
name = "appliance_test",
42-
srcs = ["blobstore_test.go"],
47+
srcs = [
48+
"blobstore_test.go",
49+
"golden_test.go",
50+
"helpers_test.go",
51+
],
52+
data = [
53+
":testdata",
54+
"//dev/tools:kubebuilder-assets",
55+
],
4356
embed = [":appliance"],
57+
env = {
58+
"KUBEBUILDER_ASSET_PATHS": "$(rlocationpaths //dev/tools:kubebuilder-assets)",
59+
},
60+
deps = [
61+
"@com_github_go_logr_stdr//:stdr",
62+
"@com_github_stretchr_testify//require",
63+
"@com_github_stretchr_testify//suite",
64+
"@io_bazel_rules_go//go/runfiles:go_default_library",
65+
"@io_k8s_api//core/v1:core",
66+
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
67+
"@io_k8s_apimachinery//pkg/runtime/schema",
68+
"@io_k8s_client_go//kubernetes",
69+
"@io_k8s_client_go//kubernetes/scheme",
70+
"@io_k8s_sigs_controller_runtime//:controller-runtime",
71+
"@io_k8s_sigs_controller_runtime//pkg/client",
72+
"@io_k8s_sigs_controller_runtime//pkg/envtest",
73+
"@io_k8s_sigs_controller_runtime//pkg/metrics/server",
74+
"@io_k8s_sigs_yaml//:yaml",
75+
],
4476
)

internal/appliance/blobstore.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ package appliance
33
import (
44
"context"
55

6+
appsv1 "k8s.io/api/apps/v1"
7+
corev1 "k8s.io/api/core/v1"
8+
"k8s.io/apimachinery/pkg/api/resource"
9+
"k8s.io/apimachinery/pkg/util/intstr"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
612
"github.com/sourcegraph/sourcegraph/internal/k8s/resource/container"
713
"github.com/sourcegraph/sourcegraph/internal/k8s/resource/deployment"
814
"github.com/sourcegraph/sourcegraph/internal/k8s/resource/pod"
915
"github.com/sourcegraph/sourcegraph/internal/k8s/resource/pvc"
1016
"github.com/sourcegraph/sourcegraph/internal/k8s/resource/service"
1117
"github.com/sourcegraph/sourcegraph/lib/errors"
1218
"github.com/sourcegraph/sourcegraph/lib/pointers"
13-
appsv1 "k8s.io/api/apps/v1"
14-
corev1 "k8s.io/api/core/v1"
15-
"k8s.io/apimachinery/pkg/api/resource"
16-
"k8s.io/apimachinery/pkg/util/intstr"
17-
"sigs.k8s.io/controller-runtime/pkg/client"
1819
)
1920

2021
func (r *Reconciler) reconcileBlobstore(ctx context.Context, sg *Sourcegraph, owner client.Object) error {
@@ -108,7 +109,8 @@ func (r *Reconciler) reconcileBlobstoreServices(ctx context.Context, sg *Sourceg
108109
func buildBlobstoreDeployment(sg *Sourcegraph) (appsv1.Deployment, error) {
109110
name := "blobstore"
110111

111-
containerImage := ""
112+
// TODO: https://github.com/sourcegraph/sourcegraph/issues/62076
113+
containerImage := "index.docker.io/sourcegraph/blobstore:5.3.2@sha256:d625be1eefe61cc42f94498e3c588bf212c4159c8b20c519db84eae4ff715efa"
112114

113115
containerPorts := corev1.ContainerPort{
114116
Name: name,
@@ -186,7 +188,7 @@ func buildBlobstoreDeployment(sg *Sourcegraph) (appsv1.Deployment, error) {
186188
},
187189
}
188190

189-
podTemplate, err := pod.NewPodTemplate(name, sg.Namespace,
191+
podTemplate, err := pod.NewPodTemplate(name,
190192
pod.WithContainers(defaultContainer),
191193
pod.WithVolumes(podVolumes),
192194
)

internal/appliance/blobstore_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,46 @@
11
package appliance
2+
3+
import (
4+
"time"
5+
)
6+
7+
// Simple test cases in which we want to assert that a given configmap causes a
8+
// certain set of resources to be deployed can go here. sg and golden fixtures
9+
// are in testdata/ and named after the test case name.
10+
func (suite *ApplianceTestSuite) TestDeployBlobstore() {
11+
for _, tc := range []struct {
12+
name string
13+
}{
14+
{
15+
name: "blobstore-default",
16+
},
17+
} {
18+
suite.Run(tc.name, func() {
19+
namespace := suite.createConfigMap(tc.name)
20+
21+
// Wait for reconciliation to be finished.
22+
suite.Require().Eventually(func() bool {
23+
return suite.getConfigMapReconcileEventCount(namespace) > 0
24+
}, time.Second*10, time.Millisecond*200)
25+
26+
suite.makeGoldenAssertions(namespace, tc.name)
27+
})
28+
}
29+
}
30+
31+
// More complex test cases involving updates to the configmap can have their own
32+
// test blocks
33+
func (suite *ApplianceTestSuite) TestBlobstoreResourcesDeletedWhenDisabled() {
34+
namespace := suite.createConfigMap("blobstore-default")
35+
suite.Require().Eventually(func() bool {
36+
return suite.getConfigMapReconcileEventCount(namespace) > 0
37+
}, time.Second*10, time.Millisecond*200)
38+
39+
eventsSeenSoFar := suite.getConfigMapReconcileEventCount(namespace)
40+
suite.updateConfigMap(namespace, "everything-disabled")
41+
suite.Require().Eventually(func() bool {
42+
return suite.getConfigMapReconcileEventCount(namespace) > eventsSeenSoFar
43+
}, time.Second*10, time.Millisecond*200)
44+
45+
suite.makeGoldenAssertions(namespace, "blobstore-subsequent-disable")
46+
}

internal/appliance/development.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Appliance development
2+
3+
## Running tests
4+
5+
To (re)generate golden fixtures, pass the following argument to `go test`:
6+
7+
```
8+
go test -args appliance-update-golden-files
9+
```
10+
11+
In order to run `go test` (with or without arguments), you must have
12+
`setup-envtest` available:
13+
14+
```
15+
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
16+
```
17+
18+
This is not a requirement for the Bazel environment (`bazel test
19+
:appliance_test` in this module).

0 commit comments

Comments
 (0)