Skip to content

Commit

Permalink
e2e: Add e2e test suite
Browse files Browse the repository at this point in the history
Adds a new e2e test suite based on the MGC repo test suite with basic
single cluster test for "simple" and "loadbalanced" type records.

Adds a new make target `make test-e2e` to execute the test suite using
AWS or GCP providers:

```
make test-e2e TEST_DNS_MANAGED_ZONE_NAME=dev-mz-aws TEST_DNS_ZONE_DOMAIN_NAME=mn.hcpapps.net TEST_DNS_NAMESPACE=dnstest TEST_DNS_PROVIDER=aws
make test-e2e TEST_DNS_MANAGED_ZONE_NAME=dev-mz-gcp TEST_DNS_ZONE_DOMAIN_NAME=mn.google.hcpapps.net TEST_DNS_NAMESPACE=dnstest TEST_DNS_PROVIDER=gcp
```
  • Loading branch information
mikenairn committed Mar 8, 2024
1 parent d6b484d commit 1405d82
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 11 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ test-unit: manifests generate fmt vet ## Run unit tests.
test-integration: manifests generate fmt vet envtest ## Run integration tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./internal/controller... -tags=integration -coverprofile cover-integration.out

.PHONY: test-e2e
test-e2e: ginkgo
$(GINKGO) -tags=e2e -v ./test/e2e

.PHONY: local-setup
local-setup: DEPLOY=false
local-setup: TEST_NAMESPACE=dnstest
Expand Down Expand Up @@ -245,6 +249,7 @@ OPENSHIFT_GOIMPORTS ?= $(LOCALBIN)/openshift-goimports
KIND = $(LOCALBIN)/kind
ACT = $(LOCALBIN)/act
YQ = $(LOCALBIN)/yq
GINKGO ?= $(LOCALBIN)/ginkgo

## Tool Versions
KUSTOMIZE_VERSION ?= v5.0.1
Expand All @@ -253,6 +258,7 @@ OPENSHIFT_GOIMPORTS_VERSION ?= c70783e636f2213cac683f6865d88c5edace3157
KIND_VERSION = v0.20.0
ACT_VERSION = latest
YQ_VERSION := v4.34.2
GINKGO_VERSION ?= v2.13.2

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
Expand Down Expand Up @@ -311,6 +317,11 @@ yq: $(YQ) ## Download yq locally if necessary.
$(YQ): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install github.com/mikefarah/yq/v4@$(YQ_VERSION)

.PHONY: ginkgo
ginkgo: $(GINKGO) ## Download ginkgo locally if necessary
$(GINKGO): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION)

.PHONY: bundle
bundle: manifests manifests-gen-base-csv kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files.
$(OPERATOR_SDK) generate kustomize manifests -q
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ kubectl logs -f deployments/dns-operator-controller-manager -n dns-operator-syst

## Development

### E2E Test Suite

The e2e test suite can be executed against any cluster running the DNS Operator with configuration added for any supported provider.

```
make test-e2e TEST_DNS_MANAGED_ZONE_NAME=<My managed zone name> TEST_DNS_ZONE_DOMAIN_NAME=<My domain name> TEST_DNS_NAMESPACE=<My test namesapace> TEST_DNS_PROVIDER=<aws|gcp>
```

| Environment Variable | Description |
|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| TEST_DNS_MANAGED_ZONE_NAME | Name of the managed zone relevant for the test domain (TEST_DNS_ZONE_DOMAIN_NAME). If using local-setup Managed zones, one of [dev-mz-aws; dev-mz-gcp] |
| TEST_DNS_ZONE_DOMAIN_NAME | Domain name being used for the test, must match the domain of the managed zone (TEST_DNS_MANAGED_ZONE_NAME) |
| TEST_DNS_NAMESPACE | The namesapce to run the test in, must be the same namesapce as the TEST_DNS_MANAGED_ZONE_NAME |
| TEST_DNS_PROVIDER | DNS Provider currently being tested, one of [aws; gcp] |

### Modifying the API definitions
If you are editing the API definitions, generate the manifests such as CRs or CRDs using:

Expand Down
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ go 1.21

require (
github.com/aws/aws-sdk-go v1.44.175
github.com/go-logr/logr v1.2.4
github.com/onsi/ginkgo/v2 v2.11.0
github.com/onsi/gomega v1.27.10
github.com/go-logr/logr v1.3.0
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e
github.com/onsi/ginkgo/v2 v2.13.2
github.com/onsi/gomega v1.30.0
github.com/prometheus/client_golang v1.17.0
google.golang.org/api v0.126.0
k8s.io/api v0.28.3
Expand Down Expand Up @@ -63,7 +64,7 @@ require (
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
Expand Down
17 changes: 10 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
Expand Down Expand Up @@ -104,6 +105,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IPRdUr28a+SK/oMchGgQy159wvzXA5tJ7l+40=
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
Expand Down Expand Up @@ -136,10 +139,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -253,8 +256,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
212 changes: 212 additions & 0 deletions test/e2e/single_cluster_record_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
//go:build e2e

package e2e

import (
"context"
"strings"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kuadrant/dns-operator/api/v1alpha1"
"github.com/kuadrant/dns-operator/internal/common/conditions"
)

var _ = Describe("Single Cluster Record Test", func() {
// testID is a randomly generated identifier for the test
// it is used to name resources and/or namespaces so different
// tests can be run in parallel in the same cluster
var testID string
// testDomainName generated domain for this test e.g. t-e2e-12345.e2e.hcpapps.net
var testDomainName string
// testHostname generated hostname for this test e.g. t-gw-mgc-12345.t-e2e-12345.e2e.hcpapps.net
var testHostname string

var dnsRecord *v1alpha1.DNSRecord
var geoCode string

BeforeEach(func(ctx SpecContext) {
testID = "t-single-" + GenerateName()
testDomainName = strings.Join([]string{testSuiteID, testZoneDomainName}, ".")
testHostname = strings.Join([]string{testID, testDomainName}, ".")

if testDNSProvider == "gcp" {
geoCode = "us-east1"
} else {
geoCode = "US"
}
})

AfterEach(func(ctx SpecContext) {
if dnsRecord != nil {
err := k8sClient.Delete(ctx, dnsRecord,
client.PropagationPolicy(metav1.DeletePropagationForeground))
Expect(client.IgnoreNotFound(err)).ToNot(HaveOccurred())
}
})

Context("simple", func() {
It("makes available a hostname that can be resolved", func(ctx SpecContext) {
By("creating a dns record")
testTargetIP := "127.0.0.1"
dnsRecord = &v1alpha1.DNSRecord{
ObjectMeta: metav1.ObjectMeta{
Name: testID,
Namespace: testNamespace,
},
Spec: v1alpha1.DNSRecordSpec{
ManagedZoneRef: &v1alpha1.ManagedZoneReference{
Name: testManagedZoneName,
},
Endpoints: []*v1alpha1.Endpoint{
{
DNSName: testHostname,
Targets: []string{
testTargetIP,
},
RecordType: "A",
RecordTTL: 60,
},
},
},
}
err := k8sClient.Create(ctx, dnsRecord)
Expect(err).ToNot(HaveOccurred())

Eventually(func(g Gomega, ctx context.Context) {
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dnsRecord), dnsRecord)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(dnsRecord.Status.Conditions).To(
ContainElement(MatchFields(IgnoreExtras, Fields{
"Type": Equal(string(conditions.ConditionTypeReady)),
"Status": Equal(metav1.ConditionTrue),
})),
)
}, 300*time.Second, 10*time.Second, ctx).Should(Succeed())

By("ensuring the authoritative nameserver resolves the hostname")
// speed up things by using the authoritative nameserver
authoritativeResolver := ResolverForDomainName(testZoneDomainName)
Eventually(func(g Gomega, ctx context.Context) {
ips, err := authoritativeResolver.LookupHost(ctx, testHostname)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(ips).To(ContainElement(testTargetIP))
}, 300*time.Second, 10*time.Second, ctx).Should(Succeed())
})
})

Context("loadbalanced", func() {
It("makes available a hostname that can be resolved", func(ctx SpecContext) {
By("creating a dns record")
testTargetIP := "127.0.0.1"

klbHostName := "klb." + testHostname
geo1KlbHostName := geoCode + "." + klbHostName
cluster1KlbHostName := "cluster1." + klbHostName

dnsRecord = &v1alpha1.DNSRecord{
ObjectMeta: metav1.ObjectMeta{
Name: "test-record",
Namespace: testNamespace,
},
Spec: v1alpha1.DNSRecordSpec{
ManagedZoneRef: &v1alpha1.ManagedZoneReference{
Name: testManagedZoneName,
},
Endpoints: []*v1alpha1.Endpoint{
{
DNSName: cluster1KlbHostName,
Targets: []string{
testTargetIP,
},
RecordType: "A",
RecordTTL: 60,
},
{
DNSName: testHostname,
Targets: []string{
klbHostName,
},
RecordType: "CNAME",
RecordTTL: 300,
},
{
DNSName: geo1KlbHostName,
Targets: []string{
cluster1KlbHostName,
},
RecordType: "CNAME",
RecordTTL: 60,
SetIdentifier: cluster1KlbHostName,
ProviderSpecific: v1alpha1.ProviderSpecific{
{
Name: "weight",
Value: "200",
},
},
},
{
DNSName: klbHostName,
Targets: []string{
geo1KlbHostName,
},
RecordType: "CNAME",
RecordTTL: 300,
SetIdentifier: geoCode,
ProviderSpecific: v1alpha1.ProviderSpecific{
{
Name: "geo-code",
Value: geoCode,
},
},
},
{
DNSName: klbHostName,
Targets: []string{
geo1KlbHostName,
},
RecordType: "CNAME",
RecordTTL: 300,
SetIdentifier: "default",
ProviderSpecific: v1alpha1.ProviderSpecific{
{
Name: "geo-code",
Value: "*",
},
},
},
},
},
}
err := k8sClient.Create(ctx, dnsRecord)
Expect(err).ToNot(HaveOccurred())

Eventually(func(g Gomega, ctx context.Context) {
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dnsRecord), dnsRecord)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(dnsRecord.Status.Conditions).To(
ContainElement(MatchFields(IgnoreExtras, Fields{
"Type": Equal(string(conditions.ConditionTypeReady)),
"Status": Equal(metav1.ConditionTrue),
})),
)
}, 300*time.Second, 10*time.Second, ctx).Should(Succeed())

By("ensuring the authoritative nameserver resolves the hostname")
// speed up things by using the authoritative nameserver
authoritativeResolver := ResolverForDomainName(testZoneDomainName)
Eventually(func(g Gomega, ctx context.Context) {
ips, err := authoritativeResolver.LookupHost(ctx, testHostname)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(ips).To(ContainElement(testTargetIP))
}, 300*time.Second, 10*time.Second, ctx).Should(Succeed())
})
})

})
Loading

0 comments on commit 1405d82

Please sign in to comment.