Skip to content

Commit

Permalink
test: add envtest for redis standalone (#748)
Browse files Browse the repository at this point in the history
Signed-off-by: Mathieu Cesbron <[email protected]>
  • Loading branch information
MathieuCesbron authored Jan 15, 2024
1 parent 7665d4a commit cd1e810
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 66 deletions.
39 changes: 20 additions & 19 deletions .github/workflows/operator-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ env:
DockerImagName: docker.io/opstree/redis-operator
BuildDocs: true
AppVersion: "v0.15.2"
DOCKERFILE_PATH: '**/Dockerfile'
DOCKERFILE_PATH: "**/Dockerfile"

jobs:
gofmt:
Expand Down Expand Up @@ -54,6 +54,8 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Install integration test dependencies
run: make integration-test-setup
- name: Run Go Tests with coverage
run: go test ./... -coverprofile=coverage.txt -covermode=atomic
- name: Upload coverage to Codecov
Expand All @@ -62,7 +64,7 @@ jobs:
file: ./coverage.txt
fail_ci_if_error: false
verbose: true

code_quality_golang_ci_lint:
needs: [gofmt, govet]
runs-on: ubuntu-latest
Expand All @@ -72,16 +74,16 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: ${{ env.GOLANG_VERSION }}

- name: Download Go modules
run: go mod download

- name: Check disk space
run: df -h

- name: List Go module cache
run: ls -la $(go env GOPATH)/pkg/mod

- name: Run GolangCI-Lint
uses: golangci/golangci-lint-action@v3
with:
Expand All @@ -105,7 +107,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
arch: ['amd64', 'arm64']
arch: ["amd64", "arm64"]
steps:
- name: Checkout Code
uses: actions/checkout@v2
Expand All @@ -125,19 +127,19 @@ jobs:
needs: [container_quality_dockerfile_lint]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout
uses: actions/checkout@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Build multi-arch image
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/arm64,linux/amd64
push: false
tags: ${{ env.DockerImagName }}:latest
- name: Build multi-arch image
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/arm64,linux/amd64
push: false
tags: ${{ env.DockerImagName }}:latest

gosec_scan:
needs: [build_go_binary]
Expand All @@ -152,4 +154,3 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

GOSEC_OUTPUT: "junit-xml:/github/workspace/gosec-results.xml"

6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,8 @@ e2e-kind-setup:

.PHONY: e2e-test
e2e-test: e2e-kind-setup install-kuttl
$(shell pwd)/bin/kuttl test --config tests/_config/kuttl-test.yaml
$(shell pwd)/bin/kuttl test --config tests/_config/kuttl-test.yaml

.PHONY: integration-test-setup
integration-test-setup:
./hack/integrationSetup.sh
147 changes: 147 additions & 0 deletions controllers/redis_controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package controllers

import (
"context"
"fmt"
"time"

appsv1 "k8s.io/api/apps/v1"

redisv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/v1beta2"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

const (
ns = "default"

timeout = time.Second * 5
interval = time.Millisecond * 250
)

var _ = Describe("Redis standalone test", func() {
var (
redisCR redisv1beta2.Redis
redisCRName string
// Used to create unique name for each test
testCount int
)

JustBeforeEach(func() {
redisCR = redisv1beta2.Redis{
TypeMeta: metav1.TypeMeta{
APIVersion: "redisv1beta2/apiVersion",
Kind: "Redis",
},
ObjectMeta: metav1.ObjectMeta{
Name: redisCRName,
Namespace: ns,
},
}
Expect(k8sClient.Create(context.TODO(), &redisCR)).Should(Succeed())
testCount++
})

BeforeEach(func() {
redisCRName = fmt.Sprintf("redis-%d", testCount)
})

Context("When creating a redis standalone CR", func() {
It("should create a statefulset", func() {
var sts *appsv1.StatefulSet
Eventually(func() error {
sts = &appsv1.StatefulSet{}
return k8sClient.Get(context.TODO(), types.NamespacedName{
Name: redisCRName,
Namespace: ns,
}, sts)
}, timeout, interval).Should(BeNil())

Expect(sts.Labels).To(Equal(map[string]string{
"app": redisCRName,
"redis_setup_type": "standalone",
"role": "standalone",
}))

Expect(*sts.Spec.Replicas).To(BeEquivalentTo(1))
Expect(sts.Spec.ServiceName).To(Equal(redisCRName + "-headless"))
})

It("should create a service", func() {
var svc *corev1.Service
Eventually(func() error {
svc = &corev1.Service{}
return k8sClient.Get(context.TODO(), types.NamespacedName{
Name: redisCR.Name,
Namespace: ns,
}, svc)
}, timeout, interval).Should(BeNil())

Expect(svc.Labels).To(Equal(map[string]string{
"app": redisCRName,
"redis_setup_type": "standalone",
"role": "standalone",
}))
})

It("should create a headless service", func() {
var svc *corev1.Service
Eventually(func() error {
svc = &corev1.Service{}
return k8sClient.Get(context.TODO(), types.NamespacedName{
Name: redisCR.Name + "-headless",
Namespace: ns,
}, svc)
}, timeout, interval).Should(BeNil())

Expect(svc.Labels).To(Equal(map[string]string{
"app": redisCRName,
"redis_setup_type": "standalone",
"role": "standalone",
}))
})

It("should create additional service", func() {
var svc *corev1.Service
Eventually(func() error {
svc = &corev1.Service{}
return k8sClient.Get(context.TODO(), types.NamespacedName{
Name: redisCR.Name + "-additional",
Namespace: ns,
}, svc)
}, timeout, interval).Should(BeNil())

Expect(svc.Labels).To(Equal(map[string]string{
"app": redisCRName,
"redis_setup_type": "standalone",
"role": "standalone",
}))
})

Context("then deleting the redis standalone CR", func() {
It("should delete the statefulset", func() {
redisCR := &redisv1beta2.Redis{
ObjectMeta: metav1.ObjectMeta{
Name: redisCRName,
Namespace: ns,
},
}
Expect(k8sClient.Delete(context.TODO(), redisCR)).To(BeNil())

Eventually(func() bool {
sts := &appsv1.StatefulSet{}
err := k8sClient.Get(context.TODO(), types.NamespacedName{
Name: redisCRName,
Namespace: ns,
}, sts)
return errors.IsNotFound(err)
}, timeout, interval).Should(BeTrue())
})
})
})
})
76 changes: 50 additions & 26 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,63 +18,87 @@ package controllers

import (
"path/filepath"
"testing"
"time"

// redisv1beta1 "github.com/OT-CONTAINER-KIT/redis-operator/api/v1beta1"
redisv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/v1beta2"
. "github.com/onsi/ginkgo"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"

// "k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
// +kubebuilder:scaffold:imports
)

// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.

// var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment

// func TestAPIs(t *testing.T) {
// RegisterFailHandler(Fail)
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)

// RunSpecsWithDefaultAndCustomReporters(t,
// "Controller Suite",
// []Reporter{printer.NewlineReporter{}})
// }
RunSpecs(t, "Controller suite")
}

var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))

By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
CRDInstallOptions: envtest.CRDInstallOptions{
MaxTime: 60 * time.Second,
},
}

cfg, err := testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())

err = redisv1beta2.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
// err = redisv1beta1.AddToScheme(scheme.Scheme)
// Expect(err).ToNot(HaveOccurred())

err = redisv1beta2.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
Expect(err).ToNot(HaveOccurred())

// +kubebuilder:scaffold:scheme

k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())

}, 60)
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())

k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
})
Expect(err).ToNot(HaveOccurred())

k8sClient, err := kubernetes.NewForConfig(cfg)
Expect(err).ToNot(HaveOccurred())

err = (&RedisReconciler{
Client: k8sManager.GetClient(),
K8sClient: k8sClient,
Scheme: k8sManager.GetScheme(),
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

go func() {
defer GinkgoRecover()
err = k8sManager.Start(ctrl.SetupSignalHandler())
Expect(err).ToNot(HaveOccurred(), "failed to run manager")
gexec.KillAndWait(4 * time.Second)

// Teardown the test environment once controller is fnished.
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
}()

var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
Loading

0 comments on commit cd1e810

Please sign in to comment.