Skip to content

Commit

Permalink
✨ Add integration tests for both controllers (#79)
Browse files Browse the repository at this point in the history
* Add integration tests for both controllers

Signed-off-by: michal.gubricky <[email protected]>

* Update internal/test/integration/github/integration_test.go

Co-authored-by: Roman Hros <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>

* Update internal/test/integration/github/integration_test.go

Co-authored-by: Roman Hros <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>

* Update internal/test/integration/github/integration_test.go

Co-authored-by: Roman Hros <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>

* Update internal/test/integration/openstack/integration_controller_test.go

Co-authored-by: Roman Hros <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>

* Update internal/test/integration/openstack/integration_controller_test.go

Co-authored-by: Roman Hros <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>

* Update internal/test/integration/openstack/integration_controller_test.go

Co-authored-by: Roman Hros <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>

* Change GIT_ORG_NAME to SovereignCloudStack

Signed-off-by: michal.gubricky <[email protected]>

* Remove kind cluster logic and rename file

Signed-off-by: michal.gubricky <[email protected]>

---------

Signed-off-by: michal.gubricky <[email protected]>
Signed-off-by: Michal Gubricky <[email protected]>
Co-authored-by: Roman Hros <[email protected]>
  • Loading branch information
michal-gubricky and chess-knight authored Feb 12, 2024
1 parent 76702f8 commit 2e4b501
Show file tree
Hide file tree
Showing 30 changed files with 5,985 additions and 11 deletions.
16 changes: 9 additions & 7 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,17 @@ jobs:
- name: Running unit tests
run: make test-unit

- name: Running integration tests
env:
GIT_PROVIDER: github
GIT_ORG_NAME: SovereignCloudStack
GIT_REPOSITORY_NAME: cluster-stacks
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
ENCODED_CLOUDS_YAML: ${{ secrets.ENCODED_CLOUDS_YAML }}
run: make test-integration

# - name: Create Report
# run: make report-cover-html report-cover-treemap
# - name: Running integration tests
# env:
# GIT_PROVIDER: github
# GIT_ORG_NAME: sovereignCloudStack
# GIT_REPOSITORY_NAME: fake-cluster-stacks
# GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
# run: make test-integration

# - name: Test Summary
# uses: test-summary/action@62bc5c68de2a6a0d02039763b8c754569df99e3f # v2.1
Expand Down
22 changes: 19 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -528,16 +528,32 @@ generate-modules-ci: generate-modules

KUBEBUILDER_ASSETS ?= $(shell $(SETUP_ENVTEST) use --use-env --bin-dir $(abspath $(TOOLS_BIN_DIR)) -p path $(KUBEBUILDER_ENVTEST_KUBERNETES_VERSION))

.PHONY: test-integration ## Run integration tests
test-integration: test-integration-github test-integration-openstack
echo done

.PHONY: test-unit
test-unit: test-unit-openstack ## Run unit tests
echo done

.PHONY: test-unit-openstack
test-unit-openstack: $(SETUP_ENVTEST) $(GOTESTSUM) $(HELM)
@mkdir -p $(shell pwd)/.coverage
CREATE_KIND_CLUSTER=false KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GOTESTSUM) --junitfile=.coverage/junit.xml --format testname -- -mod=vendor \
KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GOTESTSUM) --junitfile=.coverage/junit.xml --format testname -- -mod=vendor \
-covermode=atomic -coverprofile=.coverage/cover.out -p=4 ./internal/controller/...

.PHONY: test-integration-github
test-integration-github: $(SETUP_ENVTEST) $(GOTESTSUM)
@mkdir -p $(shell pwd)/.coverage
KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GOTESTSUM) --junitfile=.coverage/junit.xml --format testname -- -mod=vendor \
-covermode=atomic -coverprofile=.coverage/cover.out -p=1 ./internal/test/integration/github/...

.PHONY: test-integration-openstack
test-integration-openstack: $(SETUP_ENVTEST) $(GOTESTSUM)
@mkdir -p $(shell pwd)/.coverage
KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GOTESTSUM) --junitfile=.coverage/junit.xml --format testname -- -mod=vendor \
-covermode=atomic -coverprofile=.coverage/cover.out -p=1 ./internal/test/integration/openstack/...

##@ Main Targets
################
# Main Targets #
Expand Down Expand Up @@ -565,8 +581,8 @@ boilerplate: generate-boilerplate ## Ensure that your files have a boilerplate h
builder-image-push: ## Build $(CONTROLLER_SHORT)-builder to a new version. For more information see README.
BUILDER_IMAGE=$(BUILDER_IMAGE) ./hack/upgrade-builder-image.sh

# .PHONY: test
# test: test-unit test-integration ## Runs all unit and integration tests.
.PHONY: test
test: test-unit test-integration ## Runs all unit and integration tests.

create-workload-cluster-openstack: $(ENVSUBST) $(KUBECTL)
cat .cluster.yaml | $(ENVSUBST) - | $(KUBECTL) apply -f -
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
k8s.io/api v0.28.4
k8s.io/apimachinery v0.28.4
k8s.io/client-go v0.28.4
k8s.io/klog/v2 v2.100.1
sigs.k8s.io/cluster-api v1.6.0
sigs.k8s.io/cluster-api-provider-openstack v0.9.0
sigs.k8s.io/controller-runtime v0.16.3
Expand Down Expand Up @@ -69,6 +70,7 @@ require (
go.uber.org/zap v1.25.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.14.0 // indirect
golang.org/x/sys v0.15.0 // indirect
Expand All @@ -84,7 +86,6 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.28.4 // indirect
k8s.io/component-base v0.28.4 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
Expand Down
194 changes: 194 additions & 0 deletions internal/test/helpers/envtest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package helpers includes helper functions important for unit and integration testing.
package helpers

import (
"context"
"fmt"
"path"
"path/filepath"
goruntime "runtime"

githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client"
githubmocks "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks"
g "github.com/onsi/ginkgo/v2"
cspov1alpha1 "github.com/sovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kerrors "k8s.io/apimachinery/pkg/util/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
"sigs.k8s.io/cluster-api/cmd/clusterctl/log"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
)

func init() {
klog.InitFlags(nil)
logger := klogr.New()

// use klog as the internal logger for this envtest environment.
log.SetLogger(logger)
// additionally force all of the controllers to use the Ginkgo logger.
ctrl.SetLogger(logger)
// add logger for ginkgo
klog.SetOutput(g.GinkgoWriter)
}

var (
scheme = runtime.NewScheme()
env *envtest.Environment
ctx = context.Background()
)

const (
// DefaultPodNamespace is default the namespace for the envtest resources.
DefaultPodNamespace = "cspo-system"
)

func init() {
// Calculate the scheme.
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(cspov1alpha1.AddToScheme(scheme))

// Get the root of the current file to use in CRD paths.
_, filename, _, _ := goruntime.Caller(0) //nolint:dogsled // external function
root := path.Join(path.Dir(filename), "..", "..", "..")

crdPaths := []string{
filepath.Join(root, "config", "crd", "bases"),
}

// Create the test environment.
env = &envtest.Environment{
Scheme: scheme,
ErrorIfCRDPathMissing: true,
CRDDirectoryPaths: crdPaths,
}
}

type (
// TestEnvironment encapsulates a Kubernetes local test environment.
TestEnvironment struct {
ctrl.Manager
client.Client
Config *rest.Config
cancel context.CancelFunc
GitHubClientFactory githubclient.Factory
GitHubClient *githubmocks.Client
}
)

// NewTestEnvironment creates a new environment spinning up a local api-server.
func NewTestEnvironment() *TestEnvironment {
config, err := env.Start()
if err != nil {
klog.Fatalf("unable to start env: %s", err)
}

// Build the controller manager.
mgr, err := ctrl.NewManager(config, ctrl.Options{
Scheme: env.Scheme,
Metrics: metricsserver.Options{BindAddress: "0"},
})
if err != nil {
klog.Fatalf("unable to create manager: %s", err)
}

// create manager pod namespace
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: DefaultPodNamespace,
},
}

if err = mgr.GetClient().Create(ctx, ns); err != nil {
klog.Fatalf("unable to create manager pod namespace: %s", err)
}

githubClient := &githubmocks.Client{}

testEnv := &TestEnvironment{
Manager: mgr,
Client: mgr.GetClient(),
Config: mgr.GetConfig(),
GitHubClientFactory: githubmocks.NewGitHubFactory(githubClient),
GitHubClient: githubClient,
}

return testEnv
}

// StartManager starts the manager and sets a cancel function into the testEnv object.
func (t *TestEnvironment) StartManager(ctx context.Context) error {
ctx, cancel := context.WithCancel(ctx)
t.cancel = cancel
if err := t.Manager.Start(ctx); err != nil {
return fmt.Errorf("failed to start manager: %w", err)
}
return nil
}

// Stop stops the manager and cancels the context.
func (t *TestEnvironment) Stop() error {
t.cancel()
if err := env.Stop(); err != nil {
return fmt.Errorf("failed to stop environment; %w", err)
}
return nil
}

// Cleanup deletes client objects.
func (t *TestEnvironment) Cleanup(ctx context.Context, objs ...client.Object) error {
errs := make([]error, 0, len(objs))
for _, o := range objs {
err := t.Client.Delete(ctx, o)
if apierrors.IsNotFound(err) {
// If the object is not found, it must've been garbage collected
// already. For example, if we delete namespace first and then
// objects within it.
continue
}
errs = append(errs, err)
}
return kerrors.NewAggregate(errs)
}

// CreateNamespace creates a namespace.
func (t *TestEnvironment) CreateNamespace(ctx context.Context, generateName string) (*corev1.Namespace, error) {
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
GenerateName: fmt.Sprintf("%s-", generateName),
Labels: map[string]string{
"testenv/original-name": generateName,
},
},
}
if err := t.Client.Create(ctx, ns); err != nil {
return nil, fmt.Errorf("failed to create namespace: %w", err)
}

return ns, nil
}
63 changes: 63 additions & 0 deletions internal/test/integration/github/integration_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package github

import (
"testing"
"time"

githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/sovereignCloudStack/cluster-stack-provider-openstack/internal/controller"
"github.com/sovereignCloudStack/cluster-stack-provider-openstack/internal/test/helpers"
ctrl "sigs.k8s.io/controller-runtime"
)

const (
timeout = time.Second * 20
interval = 1000 * time.Millisecond
)

func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}

var (
ctx = ctrl.SetupSignalHandler()
testEnv *helpers.TestEnvironment
)

var _ = BeforeSuite(func() {
testEnv = helpers.NewTestEnvironment()
Expect((&controller.OpenStackClusterStackReleaseReconciler{
Client: testEnv.Manager.GetClient(),
GitHubClientFactory: githubclient.NewFactory(),
ReleaseDirectory: "/tmp/downloads",
}).SetupWithManager(testEnv.Manager)).To(Succeed())

go func() {
defer GinkgoRecover()
Expect(testEnv.StartManager(ctx)).To(Succeed())
}()
<-testEnv.Manager.Elected()
})

var _ = AfterSuite(func() {
Expect(testEnv.Stop()).To(Succeed())
})
Loading

0 comments on commit 2e4b501

Please sign in to comment.