Skip to content

Commit

Permalink
test(e2e): implement ginkgo as e2e suite
Browse files Browse the repository at this point in the history
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
  • Loading branch information
oliverbaehler committed Oct 20, 2024
1 parent f505ba5 commit 896cb62
Show file tree
Hide file tree
Showing 49 changed files with 430 additions and 3 deletions.
File renamed without changes.
57 changes: 57 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: e2e
permissions: {}

on:
push:
branches: [ "*" ]
paths:
- '.github/workflows/e2e.yml'
- 'api/**'
- 'controllers/**'
- 'internal/**'
- 'e2e/*'
- 'Dockerfile'
- 'go.*'
- 'main.go'
- 'Makefile'
pull_request:
branches: [ "*" ]
paths:
- '.github/workflows/e2e.yml'
- 'api/**'
- 'controllers/**'
- 'internal/**'
- 'e2e/*'
- 'Dockerfile'
- 'go.*'
- 'main.go'
- 'Makefile'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
kind:
name: Kubernetes
strategy:
fail-fast: false
matrix:
k8s-version: [ 'v1.24.7', 'v1.25.3', 'v1.26.3', 'v1.27.2', 'v1.28.0', 'v1.29.0', 'v1.30.0', 'v1.31.0' ]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
with:
fetch-depth: 0
- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version-file: 'go.mod'
- uses: engineerd/setup-kind@aa272fe2a7309878ffc2a81c56cfe3ef108ae7d0 # v0.5.0
with:
skipClusterCreation: true
version: v0.14.0
- uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v3
with:
version: v3.14.2
- name: e2e testing
run: KIND_K8S_VERSION=${{ matrix.k8s-version }} make e2e
8 changes: 6 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
linters-settings:
govet:
check-shadowing: true
gci:
sections:
- standard
Expand All @@ -13,6 +11,12 @@ linters-settings:
min-occurrences: 2
cyclop:
max-complexity: 17
issues:
exclude-rules:
- path: (.+)_test.go
linters:
- revive
text: "^(dot-imports)"
linters:
enable-all: true
disable:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ controller-gen: ## Download controller-gen locally if necessary.
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_GEN_VERSION))

GINKGO := $(shell pwd)/bin/ginkgo
GINKGO_VERSION = 2.19.0
GINKGO_VERSION = v2.19.0
ginkgo: ## Download ginkgo locally if necessary.
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION))

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
15 changes: 15 additions & 0 deletions e2e-legacy/kind.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: kind.x-k8s.io/v1alpha4
networking:
apiServerAddress: "127.0.0.1"
apiServerPort: 6443
kind: Cluster
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- hostPort: 9001
containerPort: 9001
- role: worker
extraPortMappings:
- hostPort: 9002
containerPort: 9002
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
14 changes: 14 additions & 0 deletions e2e/e2e_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package e2e_test

import (
"testing"

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

func TestE2e(t *testing.T) {
t.Parallel()
RegisterFailHandler(Fail)
RunSpecs(t, "E2e Suite")
}
164 changes: 164 additions & 0 deletions e2e/global_settings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package e2e_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client"

v1beta1 "github.com/projectcapsule/capsule-proxy/api/v1beta1"
)

var _ = Describe("GlobalProxySettings", func() {
var aliceClient, bobClient *kubernetes.Clientset

BeforeEach(func() {
var err error

aliceClient, err = loadKubeConfig("alice")
Expect(err).ToNot(HaveOccurred())
bobClient, err = loadKubeConfig("bob")
Expect(err).ToNot(HaveOccurred())

// Create Global Proxy Settings
settings := []*v1beta1.GlobalProxySettings{
{
ObjectMeta: metav1.ObjectMeta{
Name: "global-proxy-settings",
Labels: e2eLabels(),
},
Spec: v1beta1.GlobalProxySettingsSpec{
Rules: []v1beta1.GlobalSubjectSpec{
{
ClusterResources: []v1beta1.ClusterResource{
{
APIGroups: []string{"rbac.authorization.k8s.io/*"},
Resources: []string{"*"},
Operations: []v1beta1.ClusterResourceOperation{v1beta1.ClusterResourceOperationList},
Selector: &metav1.LabelSelector{
MatchLabels: e2eLabels(),
},
},
{
APIGroups: []string{"capsule.clastix.io/*"},
Resources: []string{"*"},
Operations: []v1beta1.ClusterResourceOperation{v1beta1.ClusterResourceOperationList},
Selector: &metav1.LabelSelector{
MatchLabels: e2eLabels(),
},
},
},
Subjects: []v1beta1.GlobalSubject{
{
Kind: "User",
Name: "alice",
},
{
Kind: "User",
Name: "bob",
},
},
},
},
},
},
}

for _, tran := range settings {
Eventually(func() error {
tran.ResourceVersion = ""

return k8sClient.Create(context.TODO(), tran)
}).Should(Succeed())
}

// Load Alice's kubeconfig
aliceClient, err = loadKubeConfig("alice")
Expect(err).NotTo(HaveOccurred())

// Load Bob's kubeconfig
bobClient, err = loadKubeConfig("bob")
Expect(err).NotTo(HaveOccurred())
})

JustAfterEach(func() {
// Define Resources which are lifecycled after each test
resourcesToClean := []client.Object{
&v1beta1.GlobalProxySettings{},
&rbacv1.ClusterRole{},
}

Eventually(func() error {
return cleanResources(resourcesToClean, e2eSelector())
}, defaultTimeoutInterval, defaultPollInterval).Should(Succeed())
})

It("Allow listing specific clusterroles (without tenants)", func() {
roles := []*rbacv1.ClusterRole{
{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-viewer",
Labels: e2eLabels(),
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"pods"},
Verbs: []string{"list"},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant-editor",
Labels: e2eLabels(),
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"pods"},
Verbs: []string{"*"},
},
},
},
}

for _, role := range roles {
Eventually(func() error {
role.ResourceVersion = ""

return k8sClient.Create(context.Background(), role)
}).Should(Succeed())
}

listClusterRoles := func(clientset *kubernetes.Clientset) ([]string, error) {
clusterRoles, err := clientset.RbacV1().ClusterRoles().List(context.Background(), metav1.ListOptions{})
if err != nil {
return nil, err
}
var roleNames []string
for _, role := range clusterRoles.Items {
roleNames = append(roleNames, role.Name)
}

return roleNames, nil
}

// Should only list the clusterroles that are allowed by the GlobalProxySettings
expectedRoles := []string{"tenant-editor", "tenant-viewer"}

// Check Alice's access to ClusterRoles
Eventually(func() ([]string, error) {
return listClusterRoles(aliceClient)
}).Should(Equal(expectedRoles), "Alice should only have access to the specified cluster roles")

// Check Bob's access to ClusterRoles (must contain only the expected roles)
Eventually(func() ([]string, error) {
return listClusterRoles(bobClient)
}).Should(Equal(expectedRoles), "Bob should only have access to the specified cluster roles")
})
})
58 changes: 58 additions & 0 deletions e2e/suite_client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package e2e_test

import (
"context"
"time"

"sigs.k8s.io/controller-runtime/pkg/client"
)

type e2eClient struct {
client.Client
}

func (e *e2eClient) sleep() {
time.Sleep(250 * time.Millisecond)
}

func (e *e2eClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
defer e.sleep()

return e.Client.Get(ctx, key, obj, opts...)
}

func (e *e2eClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
defer e.sleep()

return e.Client.List(ctx, list, opts...)
}

func (e *e2eClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
defer e.sleep()

return e.Client.Create(ctx, obj, opts...)
}

func (e *e2eClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
defer e.sleep()

return e.Client.Delete(ctx, obj, opts...)
}

func (e *e2eClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
defer e.sleep()

return e.Client.Update(ctx, obj, opts...)
}

func (e *e2eClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
defer e.sleep()

return e.Client.Patch(ctx, obj, patch, opts...)
}

func (e *e2eClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
defer e.sleep()

return e.Client.DeleteAllOf(ctx, obj, opts...)
}
49 changes: 49 additions & 0 deletions e2e/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package e2e_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/utils/ptr"
"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"

v1beta1 "github.com/projectcapsule/capsule-proxy/api/v1beta1"
)

//nolint:gochecknoglobals
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
)

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

By("bootstrapping test environment")
testEnv = &envtest.Environment{
UseExistingCluster: ptr.To(true),
}

var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())

Expect(v1beta1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred())

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

k8sClient = &e2eClient{Client: ctrlClient}
})

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

0 comments on commit 896cb62

Please sign in to comment.