feat: add e2e test with a sample dapr application
This commit is contained in:
parent
57c1c55910
commit
be366533c7
|
@ -71,24 +71,12 @@ jobs:
|
||||||
registry: false
|
registry: false
|
||||||
node_image: kindest/node:v${{ matrix.kubernetes-version }}
|
node_image: kindest/node:v${{ matrix.kubernetes-version }}
|
||||||
config: test/e2e/kind.yaml
|
config: test/e2e/kind.yaml
|
||||||
|
- name: 'SetUp Kind Ingress'
|
||||||
|
run: |
|
||||||
|
./hack/scripts/deploy_ingress.sh
|
||||||
- name: "SetUp Dapr Kubernetes Operator OLM"
|
- name: "SetUp Dapr Kubernetes Operator OLM"
|
||||||
run: |
|
run: |
|
||||||
make olm/install
|
./hack/scripts/deploy_olm.sh
|
||||||
|
|
||||||
kubectl wait \
|
|
||||||
--namespace=olm \
|
|
||||||
--for=condition=ready \
|
|
||||||
pod \
|
|
||||||
--selector=app=olm-operator \
|
|
||||||
--timeout=90s
|
|
||||||
|
|
||||||
kubectl wait \
|
|
||||||
--namespace=olm \
|
|
||||||
--for=condition=ready \
|
|
||||||
pod \
|
|
||||||
--selector=app=catalog-operator \
|
|
||||||
--timeout=90s
|
|
||||||
|
|
||||||
- name: "Run Dapr Kubernetes Operator OLM e2e"
|
- name: "Run Dapr Kubernetes Operator OLM e2e"
|
||||||
run: |
|
run: |
|
||||||
make test/e2e/olm
|
make test/e2e/olm
|
|
@ -51,6 +51,9 @@ jobs:
|
||||||
registry: false
|
registry: false
|
||||||
node_image: kindest/node:v${{ matrix.kubernetes-version }}
|
node_image: kindest/node:v${{ matrix.kubernetes-version }}
|
||||||
config: test/e2e/kind.yaml
|
config: test/e2e/kind.yaml
|
||||||
|
- name: 'SetUp Kind Ingress'
|
||||||
|
run: |
|
||||||
|
./hack/scripts/deploy_ingress.sh
|
||||||
- name: "SetUp Dapr Kubernetes Operator"
|
- name: "SetUp Dapr Kubernetes Operator"
|
||||||
run: |
|
run: |
|
||||||
make deploy/e2e
|
make deploy/e2e
|
||||||
|
|
|
@ -8,5 +8,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
images:
|
images:
|
||||||
- name: controller
|
- name: controller
|
||||||
newName: docker.io/daprio/dapr-kubernetes-operator
|
newName: ttl.sh/57e2fb88-57e2-4344-8b69-4364dd4f8b9b
|
||||||
newTag: 0.0.2
|
newTag: 2h
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: example-ingress
|
||||||
|
#annotations:
|
||||||
|
# nginx.ingress.kubernetes.io/use-regex: "true"
|
||||||
|
# nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- http:
|
||||||
|
paths:
|
||||||
|
- pathType: Prefix
|
||||||
|
path: /
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: testing-app-service
|
||||||
|
port:
|
||||||
|
number: 80
|
90
go.mod
90
go.mod
|
@ -3,11 +3,12 @@ module github.com/dapr-sandbox/dapr-kubernetes-operator
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/anthhub/forwarder v1.1.1-0.20230315114022-63dcf7b46a1a
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible
|
github.com/evanphx/json-patch v5.6.0+incompatible
|
||||||
github.com/go-logr/logr v1.2.4
|
github.com/go-logr/logr v1.2.4
|
||||||
github.com/onsi/gomega v1.27.10
|
github.com/onsi/gomega v1.27.10
|
||||||
github.com/openshift/api v0.0.0-20230816181854-a7ca92db022a
|
github.com/openshift/api v0.0.0-20230816181854-a7ca92db022a
|
||||||
github.com/operator-framework/api v0.17.5
|
github.com/operator-framework/api v0.17.7
|
||||||
github.com/operator-framework/operator-lifecycle-manager v0.22.0
|
github.com/operator-framework/operator-lifecycle-manager v0.22.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rs/xid v1.5.0
|
github.com/rs/xid v1.5.0
|
||||||
|
@ -27,71 +28,130 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||||
|
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||||
|
github.com/containerd/containerd v1.7.0 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
|
github.com/docker/cli v23.0.1+incompatible // indirect
|
||||||
|
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||||
|
github.com/docker/docker v23.0.1+incompatible // indirect
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||||
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
|
github.com/docker/go-metrics v0.0.1 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||||
|
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||||
|
github.com/fatih/color v1.13.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
|
github.com/go-errors/errors v1.4.2 // indirect
|
||||||
|
github.com/go-gorp/gorp/v3 v3.0.5 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-logr/zapr v1.2.4 // indirect
|
github.com/go-logr/zapr v1.2.4 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.3 // indirect
|
github.com/go-openapi/swag v0.22.4 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/gnostic-models v0.6.8 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
|
github.com/google/uuid v1.3.1 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
|
github.com/gosuri/uitable v0.0.4 // indirect
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/huandu/xstrings v1.4.0 // indirect
|
github.com/huandu/xstrings v1.4.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.13 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/compress v1.16.0 // indirect
|
||||||
|
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||||
|
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||||
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
|
github.com/moby/locker v1.0.1 // indirect
|
||||||
|
github.com/moby/spdystream v0.2.0 // indirect
|
||||||
|
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.15.1 // indirect
|
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||||
github.com/prometheus/client_model v0.4.0 // indirect
|
github.com/prometheus/client_model v0.4.0 // indirect
|
||||||
github.com/prometheus/common v0.42.0 // indirect
|
github.com/prometheus/common v0.44.0 // indirect
|
||||||
github.com/prometheus/procfs v0.9.0 // indirect
|
github.com/prometheus/procfs v0.10.1 // indirect
|
||||||
|
github.com/rubenv/sql-migrate v1.3.1 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/shopspring/decimal v1.3.1 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
github.com/sirupsen/logrus v1.9.2 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
github.com/xlab/treeprint v1.2.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||||
|
go.starlark.net v0.0.0-20230814145427-12f4cb8177e4 // indirect
|
||||||
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/zap v1.24.0 // indirect
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
golang.org/x/crypto v0.12.0 // indirect
|
golang.org/x/crypto v0.12.0 // indirect
|
||||||
golang.org/x/net v0.14.0 // indirect
|
golang.org/x/net v0.14.0 // indirect
|
||||||
golang.org/x/oauth2 v0.8.0 // indirect
|
golang.org/x/oauth2 v0.11.0 // indirect
|
||||||
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.11.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
golang.org/x/term v0.11.0 // indirect
|
golang.org/x/term v0.11.0 // indirect
|
||||||
golang.org/x/text v0.12.0 // indirect
|
golang.org/x/text v0.12.0 // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||||
|
google.golang.org/grpc v1.54.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.27.3 // indirect
|
k8s.io/apiextensions-apiserver v0.27.3 // indirect
|
||||||
k8s.io/component-base v0.27.3 // indirect
|
k8s.io/apiserver v0.28.0 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
|
k8s.io/cli-runtime v0.28.0 // indirect
|
||||||
|
k8s.io/component-base v0.28.0 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20230816210353-14e408962443 // indirect
|
||||||
|
k8s.io/kubectl v0.28.0 // indirect
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||||
|
oras.land/oras-go v1.2.3 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||||
|
sigs.k8s.io/kustomize/api v0.14.0 // indirect
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.14.3 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
|
||||||
|
|
||||||
|
kubectl wait \
|
||||||
|
--namespace=ingress-nginx \
|
||||||
|
--for=condition=ready \
|
||||||
|
pod \
|
||||||
|
--selector=app.kubernetes.io/component=controller \
|
||||||
|
--timeout=90s
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
make olm/install
|
||||||
|
|
||||||
|
kubectl wait \
|
||||||
|
--namespace=olm \
|
||||||
|
--for=condition=ready \
|
||||||
|
pod \
|
||||||
|
--selector=app=olm-operator \
|
||||||
|
--timeout=90s
|
||||||
|
|
||||||
|
kubectl wait \
|
||||||
|
--namespace=olm \
|
||||||
|
--for=condition=ready \
|
||||||
|
pod \
|
||||||
|
--selector=app=catalog-operator \
|
||||||
|
--timeout=90s
|
|
@ -0,0 +1,94 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/pointer"
|
||||||
|
netv1 "k8s.io/api/networking/v1"
|
||||||
|
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/test/support"
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/test/support/helm"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ValidateDaprApp(test support.Test, namespace string) {
|
||||||
|
test.T().Helper()
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install Dapr Test App
|
||||||
|
//
|
||||||
|
|
||||||
|
test.InstallChart(
|
||||||
|
"oci://docker.io/salaboy/testing-app",
|
||||||
|
helm.WithInstallName("testing-app"),
|
||||||
|
helm.WithInstallNamespace(namespace),
|
||||||
|
helm.WithInstallVersion("v0.1.0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
test.Eventually(support.Deployment(test, "testing-app-deployment", namespace), support.TestTimeoutShort).Should(
|
||||||
|
gomega.WithTransform(support.ConditionStatus(appsv1.DeploymentAvailable), gomega.Equal(corev1.ConditionTrue)),
|
||||||
|
)
|
||||||
|
test.Eventually(support.Service(test, "testing-app-service", namespace), support.TestTimeoutShort).Should(
|
||||||
|
gomega.Not(gomega.BeNil()),
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Expose app
|
||||||
|
//
|
||||||
|
|
||||||
|
ing := test.SetUpIngress(namespace, netv1.HTTPIngressPath{
|
||||||
|
PathType: pointer.Any(netv1.PathTypePrefix),
|
||||||
|
Path: "/",
|
||||||
|
Backend: netv1.IngressBackend{
|
||||||
|
Service: &netv1.IngressServiceBackend{
|
||||||
|
Name: "testing-app-service",
|
||||||
|
Port: netv1.ServiceBackendPort{
|
||||||
|
Number: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
test.Eventually(support.Ingress(test, ing.Name, ing.Namespace), support.TestTimeoutLong).Should(
|
||||||
|
gomega.WithTransform(
|
||||||
|
support.ExtractFirstLoadBalancerIngressHostname(),
|
||||||
|
gomega.Equal("localhost")),
|
||||||
|
"Failure to set-up ingress")
|
||||||
|
|
||||||
|
//
|
||||||
|
// Test the app
|
||||||
|
//
|
||||||
|
|
||||||
|
test.T().Log("test app")
|
||||||
|
|
||||||
|
base := fmt.Sprintf("http://localhost:%d", 8081)
|
||||||
|
|
||||||
|
//nolint:bodyclose
|
||||||
|
test.Eventually(test.GET(base+"/read"), support.TestTimeoutLong).Should(
|
||||||
|
gomega.And(
|
||||||
|
gomega.HaveHTTPStatus(http.StatusOK),
|
||||||
|
gomega.HaveHTTPBody(gomega.MatchJSON(`{ "Values": null }`)),
|
||||||
|
),
|
||||||
|
"Failure to invoke initial read",
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:bodyclose
|
||||||
|
test.Eventually(test.POST(base+"/write?message=hello", "text/plain", nil), support.TestTimeoutLong).Should(
|
||||||
|
gomega.HaveHTTPStatus(http.StatusOK),
|
||||||
|
"Failure to invoke post",
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:bodyclose
|
||||||
|
test.Eventually(test.GET(base+"/read"), support.TestTimeoutLong).Should(
|
||||||
|
gomega.And(
|
||||||
|
gomega.HaveHTTPStatus(http.StatusOK),
|
||||||
|
gomega.HaveHTTPBody(gomega.MatchJSON(`{ "Values":["hello"] }`)),
|
||||||
|
),
|
||||||
|
"Failure to invoke read",
|
||||||
|
)
|
||||||
|
}
|
|
@ -10,8 +10,8 @@ nodes:
|
||||||
node-labels: "ingress-ready=true"
|
node-labels: "ingress-ready=true"
|
||||||
extraPortMappings:
|
extraPortMappings:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
hostPort: 80
|
hostPort: 8081
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- containerPort: 443
|
- containerPort: 443
|
||||||
hostPort: 443
|
hostPort: 8443
|
||||||
protocol: TCP
|
protocol: TCP
|
|
@ -5,6 +5,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/internal/controller/operator"
|
||||||
|
daprAc "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/client/operator/applyconfiguration/operator/v1alpha1"
|
||||||
|
daprTC "github.com/dapr-sandbox/dapr-kubernetes-operator/test/e2e/common"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
@ -126,4 +131,30 @@ func TestDaprDeploy(t *testing.T) {
|
||||||
test.Eventually(Deployment(test, "dapr-control-plane", sub.Namespace), TestTimeoutLong).Should(
|
test.Eventually(Deployment(test, "dapr-control-plane", sub.Namespace), TestTimeoutLong).Should(
|
||||||
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dapr
|
||||||
|
//
|
||||||
|
|
||||||
|
instance := test.NewNamespacedNameDaprControlPlane(
|
||||||
|
types.NamespacedName{
|
||||||
|
Name: operator.DaprControlPlaneName,
|
||||||
|
Namespace: sub.Namespace,
|
||||||
|
},
|
||||||
|
daprAc.DaprControlPlaneSpec().
|
||||||
|
WithValues(nil),
|
||||||
|
)
|
||||||
|
|
||||||
|
test.Eventually(Deployment(test, "dapr-operator", instance.Namespace), TestTimeoutLong).Should(
|
||||||
|
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
||||||
|
test.Eventually(Deployment(test, "dapr-sentry", instance.Namespace), TestTimeoutLong).Should(
|
||||||
|
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
||||||
|
test.Eventually(Deployment(test, "dapr-sidecar-injector", instance.Namespace), TestTimeoutLong).Should(
|
||||||
|
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dapr Application
|
||||||
|
//
|
||||||
|
|
||||||
|
daprTC.ValidateDaprApp(test, instance.Namespace)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
daprCP "github.com/dapr-sandbox/dapr-kubernetes-operator/internal/controller/operator"
|
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
|
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
@ -14,7 +13,9 @@ import (
|
||||||
. "github.com/dapr-sandbox/dapr-kubernetes-operator/test/support"
|
. "github.com/dapr-sandbox/dapr-kubernetes-operator/test/support"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
daprCP "github.com/dapr-sandbox/dapr-kubernetes-operator/internal/controller/operator"
|
||||||
daprAc "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/client/operator/applyconfiguration/operator/v1alpha1"
|
daprAc "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/client/operator/applyconfiguration/operator/v1alpha1"
|
||||||
|
daprTC "github.com/dapr-sandbox/dapr-kubernetes-operator/test/e2e/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDaprDeploy(t *testing.T) {
|
func TestDaprDeploy(t *testing.T) {
|
||||||
|
@ -31,6 +32,11 @@ func TestDaprDeploy(t *testing.T) {
|
||||||
test.Eventually(Deployment(test, "dapr-sidecar-injector", instance.Namespace), TestTimeoutLong).Should(
|
test.Eventually(Deployment(test, "dapr-sidecar-injector", instance.Namespace), TestTimeoutLong).Should(
|
||||||
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
WithTransform(ConditionStatus(appsv1.DeploymentAvailable), Equal(corev1.ConditionTrue)))
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dapr Application
|
||||||
|
//
|
||||||
|
|
||||||
|
daprTC.ValidateDaprApp(test, instance.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDaprDeployWrongCR(t *testing.T) {
|
func TestDaprDeployWrongCR(t *testing.T) {
|
||||||
|
|
|
@ -5,10 +5,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
olmAC "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/test/support/helm"
|
||||||
|
|
||||||
daprCP "github.com/dapr-sandbox/dapr-kubernetes-operator/internal/controller/operator"
|
olmAC "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
|
||||||
daprAC "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/client/operator/clientset/versioned/typed/operator/v1alpha1"
|
|
||||||
|
|
||||||
daprClient "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/client/operator/clientset/versioned"
|
daprClient "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/client/operator/clientset/versioned"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
@ -23,16 +22,16 @@ type Client struct {
|
||||||
kubernetes.Interface
|
kubernetes.Interface
|
||||||
|
|
||||||
Dapr daprClient.Interface
|
Dapr daprClient.Interface
|
||||||
DaprCP daprAC.DaprControlPlaneInterface
|
|
||||||
Discovery discovery.DiscoveryInterface
|
Discovery discovery.DiscoveryInterface
|
||||||
OLM olmAC.Interface
|
OLM olmAC.Interface
|
||||||
|
Helm *helm.Helm
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
scheme *runtime.Scheme
|
scheme *runtime.Scheme
|
||||||
config *rest.Config
|
config *rest.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClient() (*Client, error) {
|
func newClient(logFn func(string, ...interface{})) (*Client, error) {
|
||||||
kc := os.Getenv("KUBECONFIG")
|
kc := os.Getenv("KUBECONFIG")
|
||||||
if kc == "" {
|
if kc == "" {
|
||||||
home := homedir.HomeDir()
|
home := homedir.HomeDir()
|
||||||
|
@ -69,12 +68,17 @@ func newClient() (*Client, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hClient, err := helm.New(helm.WithLog(logFn))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
c := Client{
|
c := Client{
|
||||||
Interface: kubeClient,
|
Interface: kubeClient,
|
||||||
Discovery: discoveryClient,
|
Discovery: discoveryClient,
|
||||||
Dapr: dClient,
|
Dapr: dClient,
|
||||||
DaprCP: dClient.OperatorV1alpha1().DaprControlPlanes(daprCP.DaprControlPlaneNamespaceDefault),
|
|
||||||
OLM: oClient,
|
OLM: oClient,
|
||||||
|
Helm: hClient,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"helm.sh/helm/v3/pkg/action"
|
||||||
|
"helm.sh/helm/v3/pkg/cli"
|
||||||
|
"helm.sh/helm/v3/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReleaseOptions[T any] struct {
|
||||||
|
Client *T
|
||||||
|
Values map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigurationOption func(*action.Configuration)
|
||||||
|
|
||||||
|
func WithLog(value func(string, ...interface{})) ConfigurationOption {
|
||||||
|
return func(opt *action.Configuration) {
|
||||||
|
opt.Log = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(options ...ConfigurationOption) (*Helm, error) {
|
||||||
|
|
||||||
|
settings := cli.New()
|
||||||
|
config := action.Configuration{}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(&config)
|
||||||
|
}
|
||||||
|
|
||||||
|
registryClient, err := registry.NewClient(
|
||||||
|
registry.ClientOptDebug(settings.Debug),
|
||||||
|
registry.ClientOptEnableCache(true),
|
||||||
|
registry.ClientOptWriter(os.Stdout),
|
||||||
|
registry.ClientOptCredentialsFile(settings.RegistryConfig),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.RegistryClient = registryClient
|
||||||
|
|
||||||
|
err = config.Init(settings.RESTClientGetter(), settings.Namespace(), "memory", config.Log)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
h := Helm{
|
||||||
|
settings: settings,
|
||||||
|
config: &config,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Helm struct {
|
||||||
|
settings *cli.EnvSettings
|
||||||
|
config *action.Configuration
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/utils/mergemap"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
"helm.sh/helm/v3/pkg/action"
|
||||||
|
"helm.sh/helm/v3/pkg/chart/loader"
|
||||||
|
"helm.sh/helm/v3/pkg/release"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstallOption func(*ReleaseOptions[action.Install])
|
||||||
|
|
||||||
|
func (h *Helm) Install(ctx context.Context, chart string, options ...InstallOption) (*release.Release, error) {
|
||||||
|
client := action.NewInstall(h.config)
|
||||||
|
client.ReleaseName = xid.New().String()
|
||||||
|
client.CreateNamespace = true
|
||||||
|
client.Devel = true
|
||||||
|
client.IncludeCRDs = true
|
||||||
|
client.Wait = true
|
||||||
|
client.Namespace = xid.New().String()
|
||||||
|
client.Timeout = 10 * time.Minute
|
||||||
|
|
||||||
|
io := ReleaseOptions[action.Install]{
|
||||||
|
Client: client,
|
||||||
|
Values: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(&io)
|
||||||
|
}
|
||||||
|
|
||||||
|
cp, err := client.ChartPathOptions.LocateChart(chart, h.settings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check chart dependencies to make sure all are present in /charts
|
||||||
|
chartRequested, err := loader.Load(cp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.RunWithContext(
|
||||||
|
ctx,
|
||||||
|
chartRequested,
|
||||||
|
mergemap.Merge(map[string]interface{}{}, io.Values),
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/utils/mergemap"
|
||||||
|
"helm.sh/helm/v3/pkg/action"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithInstallName(value string) InstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Install]) {
|
||||||
|
install.Client.ReleaseName = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithInstallNamespace(value string) InstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Install]) {
|
||||||
|
install.Client.Namespace = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithInstallValue(name string, value interface{}) InstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Install]) {
|
||||||
|
install.Values[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithInstallVersion(value string) InstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Install]) {
|
||||||
|
install.Client.Version = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithInstallValues(values map[string]interface{}) InstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Install]) {
|
||||||
|
install.Values = mergemap.Merge(install.Values, values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithInstallTimeout(value time.Duration) InstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Install]) {
|
||||||
|
install.Client.Timeout = value
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"helm.sh/helm/v3/pkg/action"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UninstallOption func(*ReleaseOptions[action.Uninstall])
|
||||||
|
|
||||||
|
func (h *Helm) Uninstall(_ context.Context, name string, options ...UninstallOption) error {
|
||||||
|
client := action.NewUninstall(h.config)
|
||||||
|
client.DeletionPropagation = "foreground"
|
||||||
|
client.KeepHistory = false
|
||||||
|
|
||||||
|
io := ReleaseOptions[action.Uninstall]{
|
||||||
|
Client: client,
|
||||||
|
Values: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(&io)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := client.Run(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"helm.sh/helm/v3/pkg/action"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithUninstallTimeout(value time.Duration) UninstallOption {
|
||||||
|
return func(install *ReleaseOptions[action.Uninstall]) {
|
||||||
|
install.Client.Timeout = value
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
package support
|
|
||||||
|
|
||||||
func NewHelm() (*Helm, error) {
|
|
||||||
|
|
||||||
h := Helm{}
|
|
||||||
|
|
||||||
return &h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Helm struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Helm) Install() error {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -3,6 +3,8 @@ package support
|
||||||
import (
|
import (
|
||||||
"github.com/onsi/gomega"
|
"github.com/onsi/gomega"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
netv1 "k8s.io/api/networking/v1"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
@ -22,3 +24,61 @@ func Deployment(t Test, name string, namespace string) func(g gomega.Gomega) (*a
|
||||||
return answer, err
|
return answer, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Pod(t Test, name string, namespace string) func(g gomega.Gomega) (*corev1.Pod, error) {
|
||||||
|
return func(g gomega.Gomega) (*corev1.Pod, error) {
|
||||||
|
answer, err := t.Client().CoreV1().Pods(namespace).Get(
|
||||||
|
t.Ctx(),
|
||||||
|
name,
|
||||||
|
metav1.GetOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
if k8serrors.IsNotFound(err) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Service(t Test, name string, namespace string) func(g gomega.Gomega) (*corev1.Service, error) {
|
||||||
|
return func(g gomega.Gomega) (*corev1.Service, error) {
|
||||||
|
answer, err := t.Client().CoreV1().Services(namespace).Get(
|
||||||
|
t.Ctx(),
|
||||||
|
name,
|
||||||
|
metav1.GetOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
if k8serrors.IsNotFound(err) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ingress(t Test, name string, namespace string) func(g gomega.Gomega) (*netv1.Ingress, error) {
|
||||||
|
return func(g gomega.Gomega) (*netv1.Ingress, error) {
|
||||||
|
answer, err := t.Client().NetworkingV1().Ingresses(namespace).Get(
|
||||||
|
t.Ctx(),
|
||||||
|
name,
|
||||||
|
metav1.GetOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
if k8serrors.IsNotFound(err) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtractFirstLoadBalancerIngressHostname() func(*netv1.Ingress) string {
|
||||||
|
return func(in *netv1.Ingress) string {
|
||||||
|
if len(in.Status.LoadBalancer.Ingress) != 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return in.Status.LoadBalancer.Ingress[0].Hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,14 @@ func ConditionStatus[T conditionType](conditionType T) func(any) corev1.Conditio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case *corev1.Pod:
|
||||||
|
if o != nil {
|
||||||
|
for i := range o.Status.Conditions {
|
||||||
|
if string(o.Status.Conditions[i].Type) == string(conditionType) {
|
||||||
|
return o.Status.Conditions[i].Status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case *v1alpha1.DaprControlPlane:
|
case *v1alpha1.DaprControlPlane:
|
||||||
if o != nil {
|
if o != nil {
|
||||||
for i := range o.Status.Conditions {
|
for i := range o.Status.Conditions {
|
||||||
|
@ -55,6 +63,14 @@ func ConditionReason[T conditionType](conditionType T) func(any) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case *corev1.Pod:
|
||||||
|
if o != nil {
|
||||||
|
for i := range o.Status.Conditions {
|
||||||
|
if string(o.Status.Conditions[i].Type) == string(conditionType) {
|
||||||
|
return o.Status.Conditions[i].Reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case *v1alpha1.DaprControlPlane:
|
case *v1alpha1.DaprControlPlane:
|
||||||
if o != nil {
|
if o != nil {
|
||||||
for i := range o.Status.Conditions {
|
for i := range o.Status.Conditions {
|
|
@ -1,9 +1,20 @@
|
||||||
package support
|
package support
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/anthhub/forwarder"
|
||||||
|
"k8s.io/client-go/tools/portforward"
|
||||||
|
|
||||||
|
"github.com/rs/xid"
|
||||||
|
netv1 "k8s.io/api/networking/v1"
|
||||||
|
|
||||||
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/test/support/helm"
|
||||||
|
|
||||||
"github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1"
|
"github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1"
|
||||||
daprCP "github.com/dapr-sandbox/dapr-kubernetes-operator/internal/controller/operator"
|
daprCP "github.com/dapr-sandbox/dapr-kubernetes-operator/internal/controller/operator"
|
||||||
|
@ -17,14 +28,21 @@ import (
|
||||||
"github.com/onsi/gomega"
|
"github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:interfacebloat
|
||||||
type Test interface {
|
type Test interface {
|
||||||
T() *testing.T
|
T() *testing.T
|
||||||
Ctx() context.Context
|
Ctx() context.Context
|
||||||
Client() *Client
|
Client() *Client
|
||||||
|
|
||||||
NewTestNamespace(...Option[*corev1.Namespace]) *corev1.Namespace
|
NewTestNamespace(...Option[*corev1.Namespace]) *corev1.Namespace
|
||||||
NewDaprControlPlane(spec *daprAc.DaprControlPlaneSpecApplyConfiguration) *v1alpha1.DaprControlPlane
|
NewDaprControlPlane(*daprAc.DaprControlPlaneSpecApplyConfiguration) *v1alpha1.DaprControlPlane
|
||||||
NewNamespacedNameDaprControlPlane(types.NamespacedName, *daprAc.DaprControlPlaneSpecApplyConfiguration) *v1alpha1.DaprControlPlane
|
NewNamespacedNameDaprControlPlane(types.NamespacedName, *daprAc.DaprControlPlaneSpecApplyConfiguration) *v1alpha1.DaprControlPlane
|
||||||
|
InstallChart(string, ...helm.InstallOption)
|
||||||
|
SetUpIngress(string, netv1.HTTPIngressPath) *netv1.Ingress
|
||||||
|
Forward(string, string, int) (*forwarder.Result, [][]portforward.ForwardedPort, error)
|
||||||
|
|
||||||
|
GET(string) func(g gomega.Gomega) (*http.Response, error)
|
||||||
|
POST(string, string, []byte) func(g gomega.Gomega) (*http.Response, error)
|
||||||
|
|
||||||
gomega.Gomega
|
gomega.Gomega
|
||||||
}
|
}
|
||||||
|
@ -44,6 +62,8 @@ var _ Option[any] = errorOption[any](nil)
|
||||||
|
|
||||||
func With(t *testing.T) Test {
|
func With(t *testing.T) Test {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
t.Log()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if deadline, ok := t.Deadline(); ok {
|
if deadline, ok := t.Deadline(); ok {
|
||||||
withDeadline, cancel := context.WithDeadline(ctx, deadline)
|
withDeadline, cancel := context.WithDeadline(ctx, deadline)
|
||||||
|
@ -51,11 +71,18 @@ func With(t *testing.T) Test {
|
||||||
ctx = withDeadline
|
ctx = withDeadline
|
||||||
}
|
}
|
||||||
|
|
||||||
return &T{
|
answer := &T{
|
||||||
WithT: gomega.NewWithT(t),
|
WithT: gomega.NewWithT(t),
|
||||||
t: t,
|
t: t,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
answer.SetDefaultEventuallyPollingInterval(500 * time.Millisecond)
|
||||||
|
answer.SetDefaultEventuallyTimeout(TestTimeoutLong)
|
||||||
|
answer.SetDefaultConsistentlyDuration(500 * time.Millisecond)
|
||||||
|
answer.SetDefaultConsistentlyDuration(TestTimeoutLong)
|
||||||
|
|
||||||
|
return answer
|
||||||
}
|
}
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
|
@ -79,7 +106,7 @@ func (t *T) Ctx() context.Context {
|
||||||
|
|
||||||
func (t *T) Client() *Client {
|
func (t *T) Client() *Client {
|
||||||
t.once.Do(func() {
|
t.once.Do(func() {
|
||||||
c, err := newClient()
|
c, err := newClient(t.t.Logf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.T().Fatalf("Error creating client: %v", err)
|
t.T().Fatalf("Error creating client: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -118,7 +145,9 @@ func (t *T) NewNamespacedNameDaprControlPlane(
|
||||||
spec *daprAc.DaprControlPlaneSpecApplyConfiguration,
|
spec *daprAc.DaprControlPlaneSpecApplyConfiguration,
|
||||||
) *v1alpha1.DaprControlPlane {
|
) *v1alpha1.DaprControlPlane {
|
||||||
|
|
||||||
cp := t.Client().DaprCP
|
t.T().Logf("Setting up Dapr ControlPlane %s in namespace %s", nn.Name, nn.Namespace)
|
||||||
|
|
||||||
|
cp := t.Client().Dapr.OperatorV1alpha1().DaprControlPlanes(nn.Namespace)
|
||||||
|
|
||||||
instance, err := cp.Apply(
|
instance, err := cp.Apply(
|
||||||
t.Ctx(),
|
t.Ctx(),
|
||||||
|
@ -141,3 +170,129 @@ func (t *T) NewNamespacedNameDaprControlPlane(
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *T) InstallChart(
|
||||||
|
chart string,
|
||||||
|
options ...helm.InstallOption,
|
||||||
|
) {
|
||||||
|
allopt := make([]helm.InstallOption, 0)
|
||||||
|
allopt = append(allopt, options...)
|
||||||
|
allopt = append(allopt, helm.WithInstallTimeout(TestTimeoutLong))
|
||||||
|
|
||||||
|
release, err := t.Client().Helm.Install(
|
||||||
|
t.Ctx(),
|
||||||
|
chart,
|
||||||
|
allopt...)
|
||||||
|
|
||||||
|
t.Expect(err).
|
||||||
|
ToNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
t.T().Cleanup(func() {
|
||||||
|
err := t.Client().Helm.Uninstall(
|
||||||
|
t.Ctx(),
|
||||||
|
release.Name,
|
||||||
|
helm.WithUninstallTimeout(TestTimeoutLong))
|
||||||
|
|
||||||
|
t.Expect(err).
|
||||||
|
ToNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) SetUpIngress(
|
||||||
|
namespace string,
|
||||||
|
path netv1.HTTPIngressPath,
|
||||||
|
) *netv1.Ingress {
|
||||||
|
name := xid.New().String()
|
||||||
|
|
||||||
|
t.T().Logf("Setting up ingress %s in namespace %s", name, namespace)
|
||||||
|
|
||||||
|
ing, err := t.Client().NetworkingV1().Ingresses(namespace).Create(
|
||||||
|
t.Ctx(),
|
||||||
|
&netv1.Ingress{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Spec: netv1.IngressSpec{
|
||||||
|
Rules: []netv1.IngressRule{{
|
||||||
|
IngressRuleValue: netv1.IngressRuleValue{
|
||||||
|
HTTP: &netv1.HTTPIngressRuleValue{
|
||||||
|
Paths: []netv1.HTTPIngressPath{path},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
metav1.CreateOptions{},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Expect(err).
|
||||||
|
ToNot(gomega.HaveOccurred())
|
||||||
|
t.Expect(ing).
|
||||||
|
ToNot(gomega.BeNil())
|
||||||
|
|
||||||
|
t.T().Cleanup(func() {
|
||||||
|
t.Expect(
|
||||||
|
t.Client().NetworkingV1().Ingresses(namespace).Delete(
|
||||||
|
t.Ctx(),
|
||||||
|
ing.Name,
|
||||||
|
metav1.DeleteOptions{
|
||||||
|
PropagationPolicy: pointer.Any(metav1.DeletePropagationForeground),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).ToNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
return ing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) Forward(service string, namespace string, remotePort int) (*forwarder.Result, [][]portforward.ForwardedPort, error) {
|
||||||
|
options := []*forwarder.Option{{
|
||||||
|
RemotePort: remotePort,
|
||||||
|
ServiceName: service,
|
||||||
|
Namespace: namespace,
|
||||||
|
}}
|
||||||
|
|
||||||
|
ret, err := forwarder.WithRestConfig(t.Ctx(), options, t.Client().config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ports, err := ret.Ready()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, ports, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) GET(url string) func(g gomega.Gomega) (*http.Response, error) {
|
||||||
|
return func(g gomega.Gomega) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequestWithContext(t.Ctx(), http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.DefaultClient.Do(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) POST(url string, contentType string, content []byte) func(g gomega.Gomega) (*http.Response, error) {
|
||||||
|
return func(g gomega.Gomega) (*http.Response, error) {
|
||||||
|
data := content
|
||||||
|
if data == nil {
|
||||||
|
data = []byte{}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(t.Ctx(), http.MethodPost, url, bytes.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if contentType != "" {
|
||||||
|
req.Header.Add("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.DefaultClient.Do(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue