Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions Dockerfile.rhel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/capi-
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/capi-controllers .
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/machine-api-migration .
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/crd-compatibility-checker .
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/extension .

COPY ./manifests /manifests
COPY ./capi-operator-manifests /capi-operator-manifests
Expand Down
20 changes: 16 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ifeq ($(HOME), /)
HOME = /tmp/kubebuilder-testing
endif

.PHONY: help all verify test build operator migration manifests-gen ocp-manifests unit e2e run fmt vet lint vendor image push aws-cluster azure-cluster gcp-cluster powervs-cluster vsphere-cluster
.PHONY: help all verify test build operator migration manifests-gen ocp-manifests unit e2e run fmt vet lint vendor image push aws-cluster azure-cluster gcp-cluster powervs-cluster vsphere-cluster extension ote-test
.DEFAULT_GOAL := build

help: ## Display this help message
Expand All @@ -29,7 +29,7 @@ verify: fmt lint verify-ocp-manifests ## Run formatting and linting checks

test: verify unit ## Run verification and unit tests

build: bin/capi-operator bin/capi-controllers bin/machine-api-migration bin/crd-compatibility-checker manifests-gen ## Build all binaries
build: bin/capi-operator bin/capi-controllers bin/machine-api-migration bin/crd-compatibility-checker manifests-gen extension ## Build all binaries

# Ensure bin directory exists for build outputs
bin/:
Expand Down Expand Up @@ -69,8 +69,20 @@ unit: .localtestenv ## Run unit tests
./hack/test.sh "$(TEST_DIRS)" 20m

.PHONY: e2e
e2e: ## Run e2e tests against active kubeconfig
./hack/test.sh "./e2e/..." 120m
e2e: extension ## Run e2e tests against active kubeconfig
./bin/extension --ginkgo.timeout=120m

.PHONY: extension
extension: | bin/ ## Build OTE extension binary
cd e2e && GOWORK=off go build -mod=readonly -o ../bin/extension ./cmd/extension

.PHONY: ote-test
ote-test: extension ## Run OTE tests
./bin/extension

.PHONY: ote-test-dry-run
ote-test-dry-run: extension ## List OTE tests without running
./bin/extension --ginkgo.dry-run --ginkgo.v

run: ## Run the operator against the configured Kubernetes cluster
oc -n openshift-cluster-api patch lease cluster-capi-operator-leader -p '{"spec":{"acquireTime": null, "holderIdentity": null, "renewTime": null}}' --type=merge
Expand Down
275 changes: 275 additions & 0 deletions RUN_OTE_TESTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
# Running OTE Tests

## Prerequisites

```bash
# 1. Connect to an OpenShift cluster
export KUBECONFIG=/path/to/your/kubeconfig
oc whoami

# 2. Build the extension binary
make extension
```

## Running Tests

### 1. List all available tests

```bash
# List all tests without running them
./bin/extension --ginkgo.dry-run --ginkgo.v

# Count the number of tests
./bin/extension --ginkgo.dry-run | grep "Will run"
```

### 2. Run all tests

```bash
# Run all e2e tests
./bin/extension

# Using Makefile (equivalent)
make e2e
```

### 3. Run platform-specific tests

```bash
# Run only AWS tests
./bin/extension --ginkgo.focus="AWS"

# Run only GCP tests
./bin/extension --ginkgo.focus="GCP"

# Run only Azure tests
./bin/extension --ginkgo.focus="Azure"

# Run only vSphere tests
./bin/extension --ginkgo.focus="vSphere"

# Run only Baremetal tests
./bin/extension --ginkgo.focus="Baremetal"
```

### 4. Run migration-related tests

```bash
# Run all Machine Migration tests
./bin/extension --ginkgo.focus="Machine Migration"

# Run all MachineSet Migration tests
./bin/extension --ginkgo.focus="MachineSet Migration"

# Run MAPI Authoritative tests
./bin/extension --ginkgo.focus="MAPI Authoritative"

# Run CAPI Authoritative tests
./bin/extension --ginkgo.focus="CAPI Authoritative"

# Run VAP (Validation Admission Policy) tests
./bin/extension --ginkgo.focus="VAP"
```

### 5. Filter tests with regular expressions

```bash
# Run all tests containing "create"
./bin/extension --ginkgo.focus="create"

# Run all tests containing "update"
./bin/extension --ginkgo.focus="update"

# Skip slow tests
./bin/extension --ginkgo.skip="Slow"

# Skip disruptive tests
./bin/extension --ginkgo.skip="Disruptive"
```

### 6. Run tests in parallel

```bash
# Run tests with 4 parallel processes
./bin/extension --ginkgo.procs=4

# Note: Tests marked as Ordered will automatically run serially
```

### 7. Set timeouts

```bash
# Set timeout to 10 minutes per test
./bin/extension --ginkgo.timeout=10m

# Set timeout for the entire suite
./bin/extension --ginkgo.timeout=2h
```

### 8. Verbose output and debugging

```bash
# Show verbose output
./bin/extension --ginkgo.v

# Show test progress
./bin/extension --ginkgo.progress

# Show full stack trace on failure
./bin/extension --ginkgo.trace

# Combine options
./bin/extension --ginkgo.v --ginkgo.progress --ginkgo.trace
```

### 9. Generate test reports

```bash
# Generate JUnit XML report
./bin/extension --ginkgo.junit-report=junit.xml

# Generate JSON report
./bin/extension --ginkgo.json-report=report.json

# Generate both reports
./bin/extension \
--ginkgo.junit-report=junit.xml \
--ginkgo.json-report=report.json
```

### 10. Fail fast

```bash
# Stop after the first test failure
./bin/extension --ginkgo.fail-fast

# Stop after 3 test failures
./bin/extension --ginkgo.fail-on-pending --ginkgo.flake-attempts=3
```
Comment on lines +145 to +148
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading description: options don't match the stated behavior.

The comment says "Stop after 3 test failures" but:

  • --ginkgo.fail-on-pending causes the suite to fail if there are pending specs, not after N failures
  • --ginkgo.flake-attempts=3 retries failed tests up to 3 times before marking them as failed

To stop after the first failure, --ginkgo.fail-fast (shown above) is correct. Consider revising or removing this example.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@RUN_OTE_TESTS.md` around lines 145 - 148, The comment claiming "Stop after 3
test failures" is misleading because the flags shown (--ginkgo.fail-on-pending
and --ginkgo.flake-attempts=3) do not implement that behavior; update the
documentation to either (a) correct the description to explain that
--ginkgo.flake-attempts=3 retries failures up to 3 times and
--ginkgo.fail-on-pending fails on pending specs, or (b) replace the example with
the correct flag (--ginkgo.fail-fast) if you intend to stop on the first
failure; mention the exact flags (--ginkgo.fail-on-pending,
--ginkgo.flake-attempts, --ginkgo.fail-fast) so the maintainer can locate and
edit the example accordingly.


## Common Usage Patterns

### Quick validation (single platform)

```bash
# Quick validation on AWS
./bin/extension \
--ginkgo.focus="AWS" \
--ginkgo.fail-fast \
--ginkgo.v
```

### Full CI run

```bash
# Run all tests with reports in CI environment
./bin/extension \
--ginkgo.v \
--ginkgo.progress \
--ginkgo.junit-report=junit.xml \
--ginkgo.timeout=3h \
--ginkgo.flake-attempts=2
```

### Debug a single test

```bash
# Run a specific test with verbose output
./bin/extension \
--ginkgo.focus="should be able to run a machine with a default provider spec" \
--ginkgo.v \
--ginkgo.trace
```

### Migration feature tests

```bash
# Test only migration features (requires MachineAPIMigration feature gate)
./bin/extension \
--ginkgo.focus="MachineAPIMigration" \
--ginkgo.v \
--ginkgo.progress
```

## Filter by test labels

Current test labels:
- `[sig-cluster-lifecycle]` - Cluster lifecycle related
- `[OCPFeatureGate:MachineAPIMigration]` - Requires MachineAPIMigration feature gate

```bash
# Run all sig-cluster-lifecycle tests
./bin/extension --ginkgo.focus="sig-cluster-lifecycle"

# Run tests requiring feature gates
./bin/extension --ginkgo.focus="OCPFeatureGate"
```

## Output Formats

### Default output
```
Running Suite: Cluster CAPI Operator E2E Suite
Will run 42 of 44 specs
• • • • • • • • • • • ... (42 tests)
Ran 42 of 44 Specs in 45.123 seconds
SUCCESS! -- 42 Passed | 0 Failed | 2 Pending | 0 Skipped
```

### Verbose output (-v)
```
[It] should be able to run a machine with a default provider spec
/path/to/test.go:123
• [5.234 seconds]
```

## Test result files

After running tests, the following files may be generated:
```
junit.xml # JUnit format report (for CI)
report.json # JSON format report
```

## Troubleshooting

### Issue: Tests are skipped
```bash
# Check why tests are skipped
./bin/extension --ginkgo.v --ginkgo.focus="YOUR_TEST"
```

Common reasons:
- Platform mismatch (AWS tests will be skipped on GCP clusters)
- Feature gate not enabled
- Cluster doesn't meet test requirements (e.g., SNO clusters)

### Issue: Test timeout
```bash
# Increase timeout
./bin/extension --ginkgo.timeout=30m
```

### Issue: KUBECONFIG not found
```bash
# Ensure KUBECONFIG is set
export KUBECONFIG=/path/to/kubeconfig
oc cluster-info
```

## Best Practices

1. **Local development**: Use `--ginkgo.focus` to run only the tests you care about
2. **CI environment**: Generate reports and set reasonable timeouts
3. **Debugging**: Use `-v` and `--trace` for detailed information
4. **Quick validation**: Use `--fail-fast` and focus on a specific platform

## More Options

View all available options:
```bash
./bin/extension --help
```

Ginkgo official documentation:
- https://onsi.github.io/ginkgo/
File renamed without changes.
File renamed without changes.
File renamed without changes.
22 changes: 22 additions & 0 deletions e2e/cmd/extension/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"flag"
"os"

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

// Import test packages to register tests
_ "github.com/openshift/cluster-capi-operator/e2e"
)

func main() {
flag.Parse()
gomega.RegisterFailHandler(ginkgo.Fail)

success := ginkgo.RunSpecs(ginkgo.GinkgoT(), "Cluster CAPI Operator E2E Suite")
if !success {
os.Exit(1)
}
Comment on lines +14 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Ginkgo v2 RunSpecs standalone binary GinkgoT usage pattern

💡 Result:

RunSpecs + “standalone binary” (precompiled suite) pattern (Ginkgo v2)

  1. Keep the normal suite entrypoint (still required):
func TestMySuite(t *testing.T) {
  RegisterFailHandler(Fail)
  RunSpecs(t, "My Suite")
}

RunSpecs is the Ginkgo spec-runner entrypoint and is intended to be called from a TestX(t *testing.T) function. [2]

  1. Build a standalone *.test binary and run it:
ginkgo build ./path/to/suite
# produces: package-name.test
./package-name.test          # run directly
# or
ginkgo package-name.test     # run via ginkgo

For parallel execution of a precompiled suite, invoke it via the CLI:

ginkgo -p ./path/to/suite.test

[1]


GinkgoT() usage pattern (why/when/how)

Use GinkgoT() inside your specs when a third-party library wants something *testing.T-like (or accepts it via an interface), e.g. gomock/testify:

var _ = Describe("Consumer", func() {
  var ctrl *gomock.Controller

  BeforeEach(func() {
    ctrl = gomock.NewController(GinkgoT())
  })

  It("does stuff", func() {
    // ...
  })
})

Ginkgo documents GinkgoT() specifically for plugging Ginkgo specs into libraries that expect *testing.T behavior; it also supports Cleanup() semantics (so gomock can auto-register Finish()), and for testing.TB you should use GinkgoTB(). [3]


🏁 Script executed:

find . -name "go.mod" -type f | head -5

Repository: openshift/cluster-capi-operator

Length of output: 139


🏁 Script executed:

cat ./e2e/go.mod | grep -i ginkgo

Repository: openshift/cluster-capi-operator

Length of output: 109


🏁 Script executed:

cat ./go.mod | grep -i ginkgo

Repository: openshift/cluster-capi-operator

Length of output: 197


🏁 Script executed:

head -20 e2e/cmd/extension/main.go

Repository: openshift/cluster-capi-operator

Length of output: 445


Incorrect usage of ginkgo.RunSpecs() and ginkgo.GinkgoT() in standalone binary.

According to Ginkgo v2 documentation, RunSpecs() must be called from a TestX(t *testing.T) function, not from main(). Additionally, GinkgoT() is intended exclusively for use inside test specs to pass to libraries that expect *testing.T (e.g., gomock), not as an argument to RunSpecs().

For a standalone test binary entry point, either:

  1. Create a proper test function: func TestMySuite(t *testing.T) { RegisterFailHandler(Fail); RunSpecs(t, "...") }
  2. Use ginkgo build ./path/to/suite to produce a .test binary and run it directly or via the Ginkgo CLI
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/cmd/extension/main.go` around lines 14 - 21, The current main()
incorrectly calls ginkgo.RunSpecs() with ginkgo.GinkgoT(); move the suite entry
into a proper Go test function instead: create a Test function (e.g.,
TestClusterCAPIOperatorE2E(t *testing.T)) that calls
gomega.RegisterFailHandler(ginkgo.Fail) and ginkgo.RunSpecs(t, "Cluster CAPI
Operator E2E Suite"), remove or stop using ginkgo.RunSpecs/ginkgo.GinkgoT from
main(), and ensure main() is not used to drive Ginkgo v2 suites (or remove main
entirely and build/run as a test binary).

}
2 changes: 2 additions & 0 deletions e2e/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package e2e contains end-to-end tests for cluster-capi-operator using the OpenShift Tests Extension framework.
package e2e
File renamed without changes.
17 changes: 17 additions & 0 deletions e2e/fixtures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package e2e

import (
"path/filepath"
"runtime"
)

// FixturePath returns the absolute path to a fixture file.
// It uses runtime.Caller to determine the location of the test/e2e directory.
func FixturePath(elem ...string) string {
_, filename, _, _ := runtime.Caller(0)
testE2EDir := filepath.Dir(filename)

// Build path: test/e2e/fixtures/{elem...}
parts := append([]string{testE2EDir, "fixtures"}, elem...)
return filepath.Join(parts...)
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ require (
github.com/gofrs/flock v0.12.1 // indirect
github.com/gofrs/uuid/v5 v5.3.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.7.0-rc.1 // indirect
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
github.com/golangci/go-printf-func-name v0.1.0 // indirect
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
Expand Down
Loading