Refactor kube package to use controller-runtime client instead of using kubectl CLI.

This allows to runt the tests faster
This commit is contained in:
Volodymyr Zotov
2025-08-25 22:52:17 -05:00
parent 9aac824066
commit cd03a651ad
4 changed files with 444 additions and 138 deletions

View File

@@ -1,16 +1,21 @@
package e2e
import (
"context"
"path/filepath"
"strconv"
"time"
//nolint:staticcheck // ST1001
. "github.com/onsi/ginkgo/v2"
//nolint:staticcheck // ST1001
. "github.com/onsi/gomega"
"github.com/1Password/onepassword-operator/pkg/testhelper/defaults"
"github.com/1Password/onepassword-operator/pkg/testhelper/kind"
"github.com/1Password/onepassword-operator/pkg/testhelper/kube"
"github.com/1Password/onepassword-operator/pkg/testhelper/op"
"github.com/1Password/onepassword-operator/pkg/testhelper/operator"
"github.com/1Password/onepassword-operator/pkg/testhelper/system"
)
const (
@@ -18,20 +23,29 @@ const (
vaultName = "operator-acceptance-tests"
)
var kubeClient *kube.Kube
var _ = Describe("Onepassword Operator e2e", Ordered, func() {
ctx := context.Background()
BeforeAll(func() {
kubeClient = kube.NewKubeClient(&kube.ClusterConfig{
Namespace: "default",
ManifestsDir: filepath.Join("manifests"),
})
kube.SetContextNamespace("default")
operator.BuildOperatorImage()
kind.LoadImageToKind(operatorImageName)
kube.CreateOpCredentialsSecret()
kube.CheckSecretExists("op-credentials")
kubeClient.Secret("op-credentials").CreateOpCredentials(ctx)
kubeClient.Secret("op-credentials").CheckIfExists(ctx)
kube.CreateSecretFromEnvVar("OP_CONNECT_TOKEN", "onepassword-token")
kube.CheckSecretExists("onepassword-token")
kubeClient.Secret("onepassword-token").CreateFromEnvVar(ctx, "OP_CONNECT_TOKEN")
kubeClient.Secret("onepassword-token").CheckIfExists(ctx)
kube.CreateSecretFromEnvVar("OP_SERVICE_ACCOUNT_TOKEN", "onepassword-service-account-token")
kube.CheckSecretExists("onepassword-service-account-token")
kubeClient.Secret("onepassword-service-account-token").CreateFromEnvVar(ctx, "OP_SERVICE_ACCOUNT_TOKEN")
kubeClient.Secret("onepassword-service-account-token").CheckIfExists(ctx)
operator.DeployOperator()
operator.WaitingForOperatorPod()
@@ -42,29 +56,25 @@ var _ = Describe("Onepassword Operator e2e", Ordered, func() {
operator.WaitingForConnectPod()
})
runCommonTestCases()
runCommonTestCases(ctx)
})
Context("Use the operator with Service Account", func() {
BeforeAll(func() {
kube.PatchOperatorToUseServiceAccount()
kube.DeleteSecret("login") // remove secret crated in previous test
})
runCommonTestCases()
})
//Context("Use the operator with Service Account", func() {
// BeforeAll(func() {
// kube.PatchOperatorToUseServiceAccount(struct{}{})
// kubeClient.DeleteSecret(ctx, "login") // remove secret crated in previous test
// })
//
// runCommonTestCases(ctx)
//})
})
// runCommonTestCases contains test cases that are common to both Connect and Service Account authentication methods.
func runCommonTestCases() {
func runCommonTestCases(ctx context.Context) {
It("Should create secret from manifest file", func() {
By("Creating secret `login` from 1Password item")
root, err := system.GetProjectRoot()
Expect(err).NotTo(HaveOccurred())
yamlPath := filepath.Join(root, "test", "e2e", "manifests", "secret.yaml")
kube.Apply(yamlPath)
kube.CheckSecretExists("login")
kubeClient.ApplyOnePasswordItem(ctx, "secret.yaml")
kubeClient.Secret("login").CheckIfExists(ctx)
})
It("Secret is updated after POOLING_INTERVAL", func() {
@@ -72,22 +82,31 @@ func runCommonTestCases() {
secretName := itemName
By("Creating secret `" + secretName + "` from 1Password item")
root, err := system.GetProjectRoot()
Expect(err).NotTo(HaveOccurred())
yamlPath := filepath.Join(root, "test", "e2e", "manifests", secretName+".yaml")
kube.Apply(yamlPath)
kube.CheckSecretExists(secretName)
kubeClient.ApplyOnePasswordItem(ctx, secretName+".yaml")
kubeClient.Secret(secretName).CheckIfExists(ctx)
By("Reading old password")
oldPassword, err := kube.ReadingSecretData(secretName, "password")
Expect(err).NotTo(HaveOccurred())
secret := kubeClient.Secret(secretName).Get(ctx)
oldPassword, ok := secret.Data["password"]
Expect(ok).To(BeTrue())
By("Updating `" + secretName + "` 1Password item")
err = op.UpdateItemPassword(itemName)
err := op.UpdateItemPassword(itemName)
Expect(err).NotTo(HaveOccurred())
kube.CheckSecretPasswordWasUpdated(secretName, oldPassword)
// checking that password was updated
Eventually(func(g Gomega) {
// Derive a short-lived context so this API call won't hang indefinitely.
attemptCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
secret = kubeClient.Secret(secretName).Get(attemptCtx)
g.Expect(err).NotTo(HaveOccurred())
newPassword, ok := secret.Data["password"]
g.Expect(ok).To(BeTrue())
g.Expect(newPassword).NotTo(Equal(oldPassword))
}, defaults.E2ETimeout, defaults.E2EInterval).Should(Succeed())
})
It("1Password item with `ignore-secret` doesn't pull updates to kubernetes secret", func() {
@@ -95,22 +114,43 @@ func runCommonTestCases() {
secretName := itemName
By("Creating secret `" + secretName + "` from 1Password item")
root, err := system.GetProjectRoot()
Expect(err).NotTo(HaveOccurred())
yamlPath := filepath.Join(root, "test", "e2e", "manifests", secretName+".yaml")
kube.Apply(yamlPath)
kube.CheckSecretExists(secretName)
kubeClient.ApplyOnePasswordItem(ctx, secretName+".yaml")
kubeClient.Secret(secretName).CheckIfExists(ctx)
By("Reading old password")
oldPassword, err := kube.ReadingSecretData(secretName, "password")
Expect(err).NotTo(HaveOccurred())
secret := kubeClient.Secret(secretName).Get(ctx)
oldPassword, ok := secret.Data["password"]
Expect(ok).To(BeTrue())
By("Updating `" + secretName + "` 1Password item")
err = op.UpdateItemPassword(itemName)
err := op.UpdateItemPassword(itemName)
Expect(err).NotTo(HaveOccurred())
newPassword, err := op.ReadItemPassword(itemName, vaultName)
kube.CheckSecretPasswordNotUpdated(secretName, newPassword, oldPassword)
Expect(newPassword).NotTo(Equal(oldPassword))
// checking that password was NOT updated
Eventually(func(g Gomega) {
// Derive a short-lived context so this API call won't hang indefinitely.
attemptCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
intervalStr := kubeClient.Deployment("onepassword-connect-operator").ReadEnvVar(attemptCtx, "POLLING_INTERVAL")
Expect(intervalStr).NotTo(BeEmpty())
i, err := strconv.Atoi(intervalStr)
Expect(err).NotTo(HaveOccurred())
interval := time.Duration(i) * time.Second // convert to duration in seconds
time.Sleep(interval + 2*time.Second) // wait for one polling interval + 2 seconds to make sure updated secret is pulled
secret = kubeClient.Secret(secretName).Get(attemptCtx)
g.Expect(err).NotTo(HaveOccurred())
currentPassword, ok := secret.Data["password"]
Expect(ok).To(BeTrue())
Expect(currentPassword).To(Equal(oldPassword))
Expect(currentPassword).NotTo(Equal(newPassword))
}, defaults.E2ETimeout, defaults.E2EInterval).Should(Succeed())
})
}