Compare commits

...

5 Commits

Author SHA1 Message Date
Volodymyr Zotov
94602ddd72 Fix lint errors 2025-09-05 11:34:18 -05:00
Volodymyr Zotov
292c6f0e93 Update testing doc to mention integration and unit tests under single command 2025-09-05 11:24:02 -05:00
Volodymyr Zotov
0f1293ca95 Update testing doc to merge integration and unit tests under single command 2025-09-05 11:20:08 -05:00
Volodymyr Zotov
706ebdd8b8 Copy manager.yaml from test/e2e when starting e2e tests 2025-09-05 10:40:46 -05:00
Volodymyr Zotov
bd963bcd1d Revert config/manager.yaml 2025-09-05 10:40:45 -05:00
5 changed files with 165 additions and 28 deletions

View File

@@ -74,7 +74,6 @@ spec:
- --leader-elect
- --health-probe-bind-address=:8081
image: 1password/onepassword-operator:latest
imagePullPolicy: Never
name: manager
env:
- name: OPERATOR_NAME
@@ -97,7 +96,7 @@ spec:
name: onepassword-token
key: token
- name: MANAGE_CONNECT
value: "true"
value: "false"
# Uncomment the following lines to enable service account token and comment out the OP_CONNECT_TOKEN, OP_CONNECT_HOST and MANAGE_CONNECT env vars.
# - name: OP_SERVICE_ACCOUNT_TOKEN
# valueFrom:

View File

@@ -1,20 +1,15 @@
# Testing
## Unit tests
**When**: Pure Go logic, no Kubernetes apiserver or network.
**Where**: `internal/...`, `pkg/...`
**Add files in**: `*_test.go` next to the code.
**Run**: `make test`
## Integration tests (envtest)
**When**: Controller/reconciler behavior against a mocked kubernetes cluster.
**Where**: `internal/controller/...`
**Framework**: controller-runtimes `envtest`.
## Unit & Integration tests
**When**: Unit (pure Go) and integration (controller-runtime envtest).
**Where**: `internal/...`, `pkg/...`
**Add files in**: `*_test.go` next to the code.
**Run**: `make test`
## E2E tests (kind)
**When**: Full cluster behavior (CRDs, operator image, Connect/SA flows).
**Where**: `test/e2e/...`
**When**: Full cluster behavior (CRDs, operator image, Connect/SA flows).
**Where**: `test/e2e/...`
**Add files in**: `*_test.go` next to the code.
**Framework**: Ginkgo + `pkg/testhelper`.
**Local prep**:
@@ -24,4 +19,4 @@
4. `make test-e2e`
5. Put `1password-credentials.json` into project root.
**Run**: `make test-e2e`
**Run**: `make test-e2e`

View File

@@ -1,7 +1,9 @@
package system
import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
@@ -51,3 +53,42 @@ func GetProjectRoot() (string, error) {
dir = parent
}
}
func ReplaceFile(src, dst string) error {
rootDir, err := GetProjectRoot()
if err != nil {
return err
}
// Open the source file
sourceFile, err := os.Open(filepath.Join(rootDir, src))
if err != nil {
return err
}
defer func(sourceFile *os.File) {
cerr := sourceFile.Close()
if err != nil {
err = errors.Join(err, cerr)
}
}(sourceFile)
// Create (or overwrite) the destination file
destFile, err := os.Create(filepath.Join(rootDir, dst))
if err != nil {
return err
}
defer func(destFile *os.File) {
cerr := destFile.Close()
if err != nil {
err = errors.Join(err, cerr)
}
}(destFile)
// Copy contents
if _, err = io.Copy(destFile, sourceFile); err != nil {
return err
}
// Ensure data is written to disk
return destFile.Sync()
}

View File

@@ -60,39 +60,42 @@ var _ = Describe("Onepassword Operator e2e", Ordered, func() {
kubeClient.Secret("onepassword-service-account-token").CreateFromEnvVar(ctx, "OP_SERVICE_ACCOUNT_TOKEN")
kubeClient.Secret("onepassword-service-account-token").CheckIfExists(ctx)
By("Replace manager.yaml")
err = system.ReplaceFile("test/e2e/manifests/manager.yaml", "config/manager/manager.yaml")
Expect(err).NotTo(HaveOccurred())
_, err = system.Run("make", "deploy")
Expect(err).NotTo(HaveOccurred())
kubeClient.Pod(map[string]string{"name": "onepassword-connect-operator"}).WaitingForRunningPod(ctx)
})
Context("Use the operator with Connect", func() {
BeforeAll(func() {
kubeClient.Pod(map[string]string{"app": "onepassword-connect"}).WaitingForRunningPod(ctx)
})
Context("Use the operator with Service Account", func() {
runCommonTestCases(ctx)
})
Context("Use the operator with Service Account", func() {
Context("Use the operator with Connect", func() {
BeforeAll(func() {
kubeClient.Deployment("onepassword-connect-operator").PatchEnvVars(ctx, []corev1.EnvVar{
{Name: "MANAGE_CONNECT", Value: "false"},
{Name: "MANAGE_CONNECT", Value: "true"},
{Name: "OP_CONNECT_HOST", Value: "http://onepassword-connect:8080"},
{
Name: "OP_SERVICE_ACCOUNT_TOKEN",
Name: "OP_CONNECT_TOKEN",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "onepassword-service-account-token",
Name: "onepassword-token",
},
Key: "token",
},
},
},
}, []string{"OP_CONNECT_HOST", "OP_CONNECT_TOKEN"})
}, []string{"OP_SERVICE_ACCOUNT_TOKEN"})
kubeClient.Secret("login").Delete(ctx) // remove secret crated in previous test
kubeClient.Secret("secret-ignored").Delete(ctx) // remove secret crated in previous test
kubeClient.Secret("secret-for-update").Delete(ctx) // remove secret crated in previous test
kubeClient.Pod(map[string]string{"app": "onepassword-connect"}).WaitingForRunningPod(ctx)
})
runCommonTestCases(ctx)
@@ -101,13 +104,13 @@ var _ = Describe("Onepassword Operator e2e", Ordered, func() {
// runCommonTestCases contains test cases that are common to both Connect and Service Account authentication methods.
func runCommonTestCases(ctx context.Context) {
It("Should create secret from manifest file", func() {
It("Should create kubernetes secret from manifest file", func() {
By("Creating secret `login` from 1Password item")
kubeClient.ApplyOnePasswordItem(ctx, "secret.yaml")
kubeClient.Secret("login").CheckIfExists(ctx)
})
It("Secret is updated after POOLING_INTERVAL", func() {
It("Kubernetes secret is updated after POOLING_INTERVAL, when updating item in 1Password", func() {
itemName := "secret-for-update"
secretName := itemName
@@ -139,7 +142,7 @@ func runCommonTestCases(ctx context.Context) {
}, defaults.E2ETimeout, defaults.E2EInterval).Should(Succeed())
})
It("1Password item with `ignore-secret` doesn't pull updates to kubernetes secret", func() {
It("1Password item with `ignore-secret` tag doesn't pull updates to kubernetes secret", func() {
itemName := "secret-ignored"
secretName := itemName

View File

@@ -0,0 +1,99 @@
# This manager file is used for e2e tests.
# It will be copied to `config/manager` and be used when deploying the operator in e2e tests
# The purpose of it is to increase e2e tests speed and do not introduce additional changes in original `manager.yaml`
apiVersion: v1
kind: Namespace
metadata:
labels:
control-plane: onepassword-connect-operator
app.kubernetes.io/name: namespace
app.kubernetes.io/instance: system
app.kubernetes.io/component: manager
app.kubernetes.io/created-by: onepassword-connect-operator
app.kubernetes.io/part-of: onepassword-connect-operator
app.kubernetes.io/managed-by: kustomize
name: system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: onepassword-connect-operator
namespace: system
labels:
control-plane: controller-manager
app.kubernetes.io/name: deployment
app.kubernetes.io/instance: controller-manager
app.kubernetes.io/component: manager
app.kubernetes.io/created-by: onepassword-connect-operator
app.kubernetes.io/part-of: onepassword-connect-operator
app.kubernetes.io/managed-by: kustomize
spec:
selector:
matchLabels:
name: onepassword-connect-operator
control-plane: onepassword-connect-operator
replicas: 1
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: manager
labels:
name: onepassword-connect-operator
control-plane: onepassword-connect-operator
spec:
securityContext:
runAsNonRoot: true
containers:
- command:
- /manager
args:
- --leader-elect
- --health-probe-bind-address=:8081
image: 1password/onepassword-operator:latest
imagePullPolicy: Never
name: manager
env:
- name: OPERATOR_NAME
value: "onepassword-connect-operator"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: WATCH_NAMESPACE
value: "default"
- name: POLLING_INTERVAL
value: "10"
- name: AUTO_RESTART
value: "false"
- name: OP_SERVICE_ACCOUNT_TOKEN
valueFrom:
secretKeyRef:
name: onepassword-service-account-token
key: token
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
serviceAccountName: onepassword-connect-operator
terminationGracePeriodSeconds: 10