Skip to content

Commit

Permalink
chore: Implement the initial integration tests (#7)
Browse files Browse the repository at this point in the history
* chore: Implement the initial integration tests

Signed-off-by: Leonardo Luz Almeida <[email protected]>

* fix integratino test

Signed-off-by: Leonardo Luz Almeida <[email protected]>

* add more tests

Signed-off-by: Leonardo Luz Almeida <[email protected]>

---------

Signed-off-by: Leonardo Luz Almeida <[email protected]>
  • Loading branch information
leoluz authored Jul 29, 2024
1 parent be50538 commit 39e1ff5
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 47 deletions.
1 change: 1 addition & 0 deletions api/v1alpha1/accessrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ type AccessRequestHistory struct {
// AccessRequest is the Schema for the accessrequests API
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortName=areq;areqs
type AccessRequest struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ spec:
kind: AccessRequest
listKind: AccessRequestList
plural: accessrequests
shortNames:
- areq
- areqs
singular: accessrequest
scope: Namespaced
versions:
Expand Down
9 changes: 6 additions & 3 deletions internal/controller/accessrequest_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const (
// 10. set the RequeueAfter in Result
func (r *AccessRequestReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.NewFromContext(ctx)
logger.Info("Reconciliation started", "bla", "bli")
logger.Info("Reconciliation started")

ar := &api.AccessRequest{}
if err := r.Get(ctx, req.NamespacedName, ar); err != nil {
Expand All @@ -83,7 +83,6 @@ func (r *AccessRequestReconciler) Reconcile(ctx context.Context, req ctrl.Reques
logger.Debug("Handling finalizer")
deleted, err := r.handleFinalizer(ctx, ar)
if err != nil {
logger.Error(err, "HandleFinalizer error")
return ctrl.Result{}, fmt.Errorf("error handling finalizer: %w", err)
}
// stop the reconciliation as the object was deleted
Expand Down Expand Up @@ -194,6 +193,10 @@ func (r *AccessRequestReconciler) updateStatusWithRetry(ctx context.Context, ar
if err != nil {
return err
}
// if it is already updated skip
if ar.Status.RequestState == status {
return nil
}
ar.UpdateStatus(status, details)
return r.Status().Update(ctx, ar)
})
Expand Down Expand Up @@ -273,7 +276,7 @@ func (r *AccessRequestReconciler) handleFinalizer(ctx context.Context, ar *api.A
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
err := r.Get(ctx, client.ObjectKeyFromObject(ar), ar)
if err != nil {
return err
return client.IgnoreNotFound(err)
}
controllerutil.RemoveFinalizer(ar, AccessRequestFinalizerName)
return r.Update(ctx, ar)
Expand Down
101 changes: 57 additions & 44 deletions internal/controller/accessrequest_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,73 +18,86 @@ package controller

import (
"context"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/client"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

ephemeralaccessv1alpha1 "github.com/argoproj-labs/ephemeral-access/api/v1alpha1"
api "github.com/argoproj-labs/ephemeral-access/api/v1alpha1"
)

var _ = Describe("AccessRequest Controller", func() {
Context("When reconciling a resource", func() {
const (
timeout = time.Second * 10
duration = time.Second * 10
interval = time.Millisecond * 250
)
Context("Reconciling a resource", Ordered, func() {
const resourceName = "test-resource"

ctx := context.Background()
accessrequest := &api.AccessRequest{}

typeNamespacedName := types.NamespacedName{
Name: resourceName,
Namespace: "default",
}
accessrequest := &ephemeralaccessv1alpha1.AccessRequest{}

BeforeEach(func() {
By("creating the custom resource for the Kind AccessRequest")
err := k8sClient.Get(ctx, typeNamespacedName, accessrequest)
if err != nil && errors.IsNotFound(err) {
resource := &ephemeralaccessv1alpha1.AccessRequest{
When("Creating an AccessRequest", func() {
BeforeEach(func() {
By("creating the custom resource for the Kind AccessRequest")
accessrequest = &api.AccessRequest{
TypeMeta: metav1.TypeMeta{
Kind: "",
APIVersion: "",
},
ObjectMeta: metav1.ObjectMeta{Name: resourceName, Namespace: "default"},
Spec: ephemeralaccessv1alpha1.AccessRequestSpec{
Spec: api.AccessRequestSpec{
Duration: metav1.Duration{},
TargetRoleName: "",
Application: ephemeralaccessv1alpha1.TargetApplication{},
Subjects: []ephemeralaccessv1alpha1.Subject{},
Application: api.TargetApplication{},
Subjects: []api.Subject{},
},
}
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
}
})

AfterEach(func() {
// TODO(user): Cleanup logic after each test, like removing the resource instance.
resource := &ephemeralaccessv1alpha1.AccessRequest{}
err := k8sClient.Get(ctx, typeNamespacedName, resource)
Expect(err).NotTo(HaveOccurred())

By("Cleanup the specific resource instance AccessRequest")
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
})
It("should successfully reconcile the resource", func() {
By("Reconciling the created resource")
controllerReconciler := &AccessRequestReconciler{
Client: k8sClient,
Scheme: k8sClient.Scheme(),
}

_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
// Example: If you expect a certain status condition after reconciliation, verify it here.
AfterAll(func() {
By("Delete the AccessRequest in k8s")
Expect(k8sClient.Delete(ctx, accessrequest)).To(Succeed())
})
It("Applies the resource in k8s", func() {
accessrequest.Spec.Duration = metav1.Duration{Duration: time.Second * 5}
err := k8sClient.Create(ctx, accessrequest)
Expect(err).NotTo(HaveOccurred())
})
It("Verify if it is created", func() {
Eventually(func() api.Status {
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(accessrequest), accessrequest)
Expect(err).NotTo(HaveOccurred())
return accessrequest.Status.RequestState
}, timeout, interval).ShouldNot(BeEmpty())
Expect(accessrequest.Status.History).NotTo(BeEmpty())
Expect(accessrequest.Status.History[0].RequestState).To(Equal(api.RequestedStatus))
})
It("Checks if the intermediate status is Granted", func() {
Eventually(func() api.Status {
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(accessrequest), accessrequest)
Expect(err).NotTo(HaveOccurred())
return accessrequest.Status.RequestState
}, timeout, interval).Should(Equal(api.GrantedStatus))
Expect(accessrequest.Status.ExpiresAt).NotTo(BeNil())
Expect(accessrequest.Status.History).Should(HaveLen(2))
Expect(accessrequest.Status.History[0].RequestState).To(Equal(api.RequestedStatus))
Expect(accessrequest.Status.History[1].RequestState).To(Equal(api.GrantedStatus))
})
It("Checks if the final status is Expired", func() {
Eventually(func() api.Status {
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(accessrequest), accessrequest)
Expect(err).NotTo(HaveOccurred())
return accessrequest.Status.RequestState
}, timeout, interval).Should(Equal(api.ExpiredStatus))
Expect(accessrequest.Status.History).Should(HaveLen(3))
Expect(accessrequest.Status.History[0].RequestState).To(Equal(api.RequestedStatus))
Expect(accessrequest.Status.History[1].RequestState).To(Equal(api.GrantedStatus))
Expect(accessrequest.Status.History[2].RequestState).To(Equal(api.ExpiredStatus))
})
})
})
})
25 changes: 25 additions & 0 deletions internal/controller/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package controller

import (
"context"
"fmt"
"path/filepath"
"runtime"
Expand All @@ -25,8 +26,11 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

// "github.com/onsi/gomega/gexec"

"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -42,6 +46,8 @@ import (
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
var cancel context.CancelFunc
var ctx context.Context

func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
Expand Down Expand Up @@ -77,13 +83,32 @@ var _ = BeforeSuite(func() {

// +kubebuilder:scaffold:scheme

ctx, cancel = context.WithCancel(context.Background())

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

k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
})
Expect(err).ToNot(HaveOccurred())
arReconciler := &AccessRequestReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
}
err = arReconciler.SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

go func() {
defer GinkgoRecover()
err = k8sManager.Start(ctx)
Expect(err).ToNot(HaveOccurred(), "failed to start k8s manager")
}()
})

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

0 comments on commit 39e1ff5

Please sign in to comment.