Skip to content

Commit 04b783b

Browse files
committed
Add functional test for product telemetry
Problem: Ensure product telemetry feature is tested with a functional test Solution: - Add a functional test. - Because it requires a NGF with a custom built, it only runs when ginkgo runs with its label. Testing: Ran successfully: - make test TAG=$(whoami) GINKGO_LABEL=telemetry PLUS_ENABLED=true - make test TAG=$(whoami) GINKGO_LABEL=telemetry - make test TAG=$(whoami) # here telemetry test was skipped, but all the rest ran successfully ClOSES - #1640
1 parent 799ea76 commit 04b783b

File tree

6 files changed

+391
-28
lines changed

6 files changed

+391
-28
lines changed

tests/Makefile

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ GINKGO_LABEL=
1313
GINKGO_FLAGS=
1414
NGF_VERSION=
1515
CI=false
16+
TELEMETRY_ENDPOINT=
17+
TELEMETRY_ENDPOINT_INSECURE=
1618

1719
ifneq ($(GINKGO_LABEL),)
1820
override GINKGO_FLAGS += -ginkgo.label-filter "$(GINKGO_LABEL)"
@@ -34,11 +36,11 @@ create-kind-cluster: ## Create a kind cluster
3436

3537
.PHONY: build-images
3638
build-images: ## Build NGF and NGINX images
37-
cd .. && make PREFIX=$(PREFIX) TAG=$(TAG) build-images
39+
cd .. && make PREFIX=$(PREFIX) TAG=$(TAG) TELEMETRY_ENDPOINT=$(TELEMETRY_ENDPOINT) TELEMETRY_ENDPOINT_INSECURE=$(TELEMETRY_ENDPOINT_INSECURE) build-images
3840

3941
.PHONY: build-images-with-plus
4042
build-images-with-plus: ## Build NGF and NGINX Plus images
41-
cd .. && make PREFIX=$(PREFIX) TAG=$(TAG) build-images-with-plus
43+
cd .. && make PREFIX=$(PREFIX) TAG=$(TAG) TELEMETRY_ENDPOINT=$(TELEMETRY_ENDPOINT) TELEMETRY_ENDPOINT_INSECURE=$(TELEMETRY_ENDPOINT_INSECURE) build-images-with-plus
4244

4345
.PHONY: load-images
4446
load-images: ## Load NGF and NGINX images on configured kind cluster
@@ -48,6 +50,32 @@ load-images: ## Load NGF and NGINX images on configured kind cluster
4850
load-images-with-plus: ## Load NGF and NGINX Plus images on configured kind cluster
4951
cd .. && make PREFIX=$(PREFIX) TAG=$(TAG) load-images-with-plus
5052

53+
.PHONY: update-ngf-manifest
54+
update-ngf-manifest: ## Update the NGF deployment manifest image names and imagePullPolicies
55+
cd .. \
56+
&& make generate-manifests HELM_TEMPLATE_COMMON_ARGS="\
57+
--set nginxGateway.image.repository=$(PREFIX) \
58+
--set nginxGateway.image.tag=$(TAG) \
59+
--set nginxGateway.image.pullPolicy=Never \
60+
--set nginx.image.repository=$(NGINX_PREFIX) \
61+
--set nginx.image.tag=$(TAG) \
62+
--set nginx.image.pullPolicy=Never" \
63+
&& cd -
64+
65+
.PHONY: update-ngf-manifest-with-plus
66+
update-ngf-manifest-with-plus: ## Update the NGF deployment manifest image names and imagePullPolicies including nginx-plus
67+
cd .. \
68+
&& make generate-manifests HELM_TEMPLATE_COMMON_ARGS="\
69+
--set nginxGateway.image.repository=$(PREFIX) \
70+
--set nginxGateway.image.tag=$(TAG) \
71+
--set nginxGateway.image.pullPolicy=Never \
72+
--set nginx.image.repository=$(NGINX_PLUS_PREFIX) \
73+
--set nginx.image.tag=$(TAG) \
74+
--set nginx.image.pullPolicy=Never \
75+
--set nginx.plus=true" \
76+
&& cd -
77+
78+
5179
test: ## Run the system tests against your default k8s cluster
5280
go test -v ./suite $(GINKGO_FLAGS) -args --gateway-api-version=$(GW_API_VERSION) \
5381
--gateway-api-prev-version=$(GW_API_PREV_VERSION) --image-tag=$(TAG) --version-under-test=$(NGF_VERSION) \

tests/README.md

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,29 @@ load-images Load NGF and NGINX images on configured kind clus
5555
run-tests-on-vm Run the tests on a GCP VM
5656
setup-gcp-and-run-tests Create and setup a GKE router and GCP VM for tests and run the tests
5757
test Run the system tests against your default k8s cluster
58+
update-ngf-manifest-with-plus Update the NGF deployment manifest image names and imagePullPolicies including nginx-plus
59+
update-ngf-manifest Update the NGF deployment manifest image names and imagePullPolicies
5860
```
5961

6062
**Note:** The following variables are configurable when running the below `make` commands:
6163

62-
| Variable | Default | Description |
63-
| ------------------- | ------------------------------- | -------------------------------------------------------------- |
64-
| TAG | edge | tag for the locally built NGF images |
65-
| PREFIX | nginx-gateway-fabric | prefix for the locally built NGF image |
66-
| NGINX_PREFIX | nginx-gateway-fabric/nginx | prefix for the locally built NGINX image |
67-
| NGINX_PLUS_PREFIX | nginx-gateway-fabric/nginx-plus | prefix for the locally built NGINX Plus image |
68-
| PLUS_ENABLED | false | Flag to indicate if NGINX Plus should be enabled |
69-
| PULL_POLICY | Never | NGF image pull policy |
70-
| GW_API_VERSION | 1.0.0 | version of Gateway API resources to install |
71-
| K8S_VERSION | latest | version of k8s that the tests are run on |
72-
| GW_SERVICE_TYPE | NodePort | type of Service that should be created |
73-
| GW_SVC_GKE_INTERNAL | false | specifies if the LoadBalancer should be a GKE internal service |
74-
| GINKGO_LABEL | "" | name of the ginkgo label that will filter the tests to run |
75-
| GINKGO_FLAGS | "" | other ginkgo flags to pass to the go test command |
64+
| Variable | Default | Description |
65+
|------------------------------|---------------------------------|---------------------------------------------------------------------|
66+
| TAG | edge | tag for the locally built NGF images |
67+
| PREFIX | nginx-gateway-fabric | prefix for the locally built NGF image |
68+
| NGINX_PREFIX | nginx-gateway-fabric/nginx | prefix for the locally built NGINX image |
69+
| NGINX_PLUS_PREFIX | nginx-gateway-fabric/nginx-plus | prefix for the locally built NGINX Plus image |
70+
| PLUS_ENABLED | false | Flag to indicate if NGINX Plus should be enabled |
71+
| PULL_POLICY | Never | NGF image pull policy |
72+
| GW_API_VERSION | 1.0.0 | version of Gateway API resources to install |
73+
| K8S_VERSION | latest | version of k8s that the tests are run on |
74+
| GW_SERVICE_TYPE | NodePort | type of Service that should be created |
75+
| GW_SVC_GKE_INTERNAL | false | specifies if the LoadBalancer should be a GKE internal service |
76+
| GINKGO_LABEL | "" | name of the ginkgo label that will filter the tests to run |
77+
| GINKGO_FLAGS | "" | other ginkgo flags to pass to the go test command |
78+
| TELEMETRY_ENDPOINT | Set in the main Makefile | The endpoint to which telemetry reports are sent |
79+
| TELEMETRY_ENDPOINT_INSECURE= | Set in the main Makefile | Controls whether TLS should be used when sending telemetry reports. |
80+
7681

7782
## Step 1 - Create a Kubernetes cluster
7883

@@ -126,7 +131,27 @@ Or, to build NGF with NGINX Plus enabled (NGINX Plus cert and key must exist in
126131
make build-images-with-plus load-images-with-plus TAG=$(whoami)
127132
```
128133

129-
## Step 3 - Run the tests
134+
For the telemetry test, which requires a OTel collector, build an image with the following variables set:
135+
136+
```makefile
137+
TELEMETRY_ENDPOINT=otel-collector-opentelemetry-collector.collector.svc.cluster.local:4317 TELEMETRY_ENDPOINT_INSECURE=true
138+
```
139+
140+
## Step 3 - Update Manifests for a Local Run
141+
142+
For NGINX OSS:
143+
144+
```makefile
145+
make update-ngf-manifest TAG=$(whoami)
146+
```
147+
148+
For NGINX Plus:
149+
150+
```makefile
151+
make update-ngf-manifest-with-plus TAG=$(whoami)
152+
```
153+
154+
## Step 4 - Run the tests
130155

131156
### 3a - Run the tests locally
132157

@@ -140,7 +165,7 @@ Or, to run the tests with NGINX Plus enabled:
140165
make test TAG=$(whoami) PLUS_ENABLED=true
141166
```
142167

143-
### 3b - Run the tests on a GKE cluster from a GCP VM
168+
### 4b - Run the tests on a GKE cluster from a GCP VM
144169

145170
This step only applies if you would like to run the tests on a GKE cluster from a GCP based VM.
146171

@@ -185,6 +210,14 @@ or to pass a specific flag, e.g. run a specific test, use the GINKGO_FLAGS varia
185210
make test TAG=$(whoami) GINKGO_FLAGS='-ginkgo.focus "writes the system info to a results file"'
186211
```
187212

213+
To run the telemetry test, which requires a specially built image (see above), run:
214+
215+
```makefile
216+
make test TAG=$(whoami) GINKGO_LABEL=telemetry
217+
```
218+
219+
Otherwise, the test will be skipped.
220+
188221
If you are running the tests in GCP, add your required label/ flags to `scripts/var.env`.
189222

190223
You can also modify the tests code for a similar outcome. To run a specific test, you can "focus" it by adding the `F`

tests/framework/resourcemanager.go

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,32 @@ import (
3030
"strings"
3131
"time"
3232

33+
apps "k8s.io/api/apps/v1"
3334
core "k8s.io/api/core/v1"
3435
apierrors "k8s.io/apimachinery/pkg/api/errors"
3536
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3637
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3738
"k8s.io/apimachinery/pkg/types"
3839
"k8s.io/apimachinery/pkg/util/wait"
3940
"k8s.io/apimachinery/pkg/util/yaml"
41+
"k8s.io/client-go/kubernetes"
4042
"sigs.k8s.io/controller-runtime/pkg/client"
4143
v1 "sigs.k8s.io/gateway-api/apis/v1"
4244
)
4345

4446
// ResourceManager handles creating/updating/deleting Kubernetes resources.
4547
type ResourceManager struct {
46-
K8sClient client.Client
47-
FS embed.FS
48-
TimeoutConfig TimeoutConfig
48+
K8sClient client.Client
49+
ClientGoClient kubernetes.Interface // used when k8sClient is not enough
50+
FS embed.FS
51+
TimeoutConfig TimeoutConfig
4952
}
5053

5154
// ClusterInfo holds the cluster metadata
5255
type ClusterInfo struct {
53-
K8sVersion string
56+
K8sVersion string
57+
// ID is the UID of kube-system namespace
58+
ID string
5459
MemoryPerNode string
5560
GkeInstanceType string
5661
GkeZone string
@@ -406,9 +411,89 @@ func (rm *ResourceManager) GetClusterInfo() (ClusterInfo, error) {
406411
ci.GkeZone = node.Labels["topology.kubernetes.io/zone"]
407412
}
408413

414+
var ns core.Namespace
415+
key := types.NamespacedName{Name: "kube-system"}
416+
417+
if err := rm.K8sClient.Get(ctx, key, &ns); err != nil {
418+
return *ci, fmt.Errorf("error getting kube-system namespace: %w", err)
419+
}
420+
421+
ci.ID = string(ns.UID)
422+
409423
return *ci, nil
410424
}
411425

426+
// GetPodNames returns the names of all Pods in the specified namespace that match the given labels.
427+
func (rm *ResourceManager) GetPodNames(namespace string, labels client.MatchingLabels) ([]string, error) {
428+
ctx, cancel := context.WithTimeout(context.Background(), rm.TimeoutConfig.GetTimeout)
429+
defer cancel()
430+
431+
var podList core.PodList
432+
if err := rm.K8sClient.List(
433+
ctx,
434+
&podList,
435+
client.InNamespace(namespace),
436+
labels,
437+
); err != nil {
438+
return nil, fmt.Errorf("error getting list of Pods: %w", err)
439+
}
440+
441+
names := make([]string, 0, len(podList.Items))
442+
443+
for _, pod := range podList.Items {
444+
names = append(names, pod.Name)
445+
}
446+
447+
return names, nil
448+
}
449+
450+
// GetPodLogs returns the logs from the specified Pod
451+
func (rm *ResourceManager) GetPodLogs(namespace, name string, opts *core.PodLogOptions) (string, error) {
452+
ctx, cancel := context.WithTimeout(context.Background(), rm.TimeoutConfig.GetTimeout)
453+
defer cancel()
454+
455+
req := rm.ClientGoClient.CoreV1().Pods(namespace).GetLogs(name, opts)
456+
457+
logs, err := req.Stream(ctx)
458+
if err != nil {
459+
return "", fmt.Errorf("error getting logs from Pod: %w", err)
460+
}
461+
defer logs.Close()
462+
463+
buf := new(bytes.Buffer)
464+
if _, err := buf.ReadFrom(logs); err != nil {
465+
return "", fmt.Errorf("error reading logs from Pod: %w", err)
466+
}
467+
468+
return buf.String(), nil
469+
}
470+
471+
// GetNGFDeployment returns the NGF Deployment in the specified namespace with the given release name.
472+
func (rm *ResourceManager) GetNGFDeployment(namespace, releaseName string) (*apps.Deployment, error) {
473+
ctx, cancel := context.WithTimeout(context.Background(), rm.TimeoutConfig.GetTimeout)
474+
defer cancel()
475+
476+
var deployments apps.DeploymentList
477+
478+
if err := rm.K8sClient.List(
479+
ctx,
480+
&deployments,
481+
client.InNamespace(namespace),
482+
client.MatchingLabels{
483+
"app.kubernetes.io/instance": releaseName,
484+
},
485+
); err != nil {
486+
return nil, fmt.Errorf("error getting list of Deployments: %w", err)
487+
}
488+
489+
if len(deployments.Items) != 1 {
490+
return nil, fmt.Errorf("expected 1 NGF Deployment, got %d", len(deployments.Items))
491+
}
492+
493+
deployment := deployments.Items[0]
494+
return &deployment, nil
495+
}
496+
412497
// GetReadyNGFPodNames returns the name(s) of the NGF Pod(s).
413498
func GetReadyNGFPodNames(
414499
k8sClient client.Client,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
mode: deployment
2+
replicaCount: 1
3+
config:
4+
exporters:
5+
debug:
6+
verbosity: detailed
7+
logging: {}
8+
extensions:
9+
health_check: {}
10+
memory_ballast:
11+
size_in_percentage: 40
12+
processors:
13+
batch: {}
14+
memory_limiter:
15+
check_interval: 5s
16+
limit_percentage: 80
17+
spike_limit_percentage: 25
18+
receivers:
19+
otlp:
20+
protocols:
21+
grpc:
22+
endpoint: 0.0.0.0:4317
23+
service:
24+
extensions:
25+
- health_check
26+
pipelines:
27+
traces:
28+
exporters:
29+
- debug
30+
receivers:
31+
- otlp

tests/suite/system_suite_test.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
k8sRuntime "k8s.io/apimachinery/pkg/runtime"
2222
"k8s.io/apimachinery/pkg/types"
2323
"k8s.io/apimachinery/pkg/util/wait"
24+
"k8s.io/client-go/kubernetes"
2425
ctlr "sigs.k8s.io/controller-runtime"
2526
"sigs.k8s.io/controller-runtime/pkg/client"
2627
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -100,11 +101,15 @@ func setup(cfg setupConfig, extraInstallArgs ...string) {
100101
k8sClient, err = client.New(k8sConfig, options)
101102
Expect(err).ToNot(HaveOccurred())
102103

104+
clientGoClient, err := kubernetes.NewForConfig(k8sConfig)
105+
Expect(err).ToNot(HaveOccurred())
106+
103107
timeoutConfig = framework.DefaultTimeoutConfig()
104108
resourceManager = framework.ResourceManager{
105-
K8sClient: k8sClient,
106-
FS: manifests,
107-
TimeoutConfig: timeoutConfig,
109+
K8sClient: k8sClient,
110+
ClientGoClient: clientGoClient,
111+
FS: manifests,
112+
TimeoutConfig: timeoutConfig,
108113
}
109114

110115
clusterInfo, err = resourceManager.GetClusterInfo()
@@ -197,22 +202,26 @@ func teardown() {
197202
)).To(Succeed())
198203
}
199204

200-
var _ = BeforeSuite(func() {
205+
func getDefaultSetupCfg() setupConfig {
201206
_, file, _, _ := runtime.Caller(0)
202207
fileDir := path.Join(path.Dir(file), "../")
203208
basepath := filepath.Dir(fileDir)
204209
localChartPath = filepath.Join(basepath, "deploy/helm-chart")
205210

206-
cfg := setupConfig{
211+
return setupConfig{
207212
chartPath: localChartPath,
208213
gwAPIVersion: *gatewayAPIVersion,
209214
deploy: true,
210215
}
216+
}
217+
218+
var _ = BeforeSuite(func() {
219+
cfg := getDefaultSetupCfg()
211220

212221
// If we are running the upgrade test only, then skip the initial deployment.
213222
// The upgrade test will deploy its own version of NGF.
214223
suiteConfig, _ := GinkgoConfiguration()
215-
if suiteConfig.LabelFilter == "upgrade" {
224+
if suiteConfig.LabelFilter == "upgrade" || suiteConfig.LabelFilter == "telemetry" {
216225
cfg.deploy = false
217226
}
218227

0 commit comments

Comments
 (0)