Skip to content

fix: support running unit tests without make test - #117

Open
shreyabiradar07 wants to merge 6 commits into
kruize:mvp_demofrom
shreyabiradar07:fix-unit-tests
Open

fix: support running unit tests without make test#117
shreyabiradar07 wants to merge 6 commits into
kruize:mvp_demofrom
shreyabiradar07:fix-unit-tests

Conversation

@shreyabiradar07

@shreyabiradar07 shreyabiradar07 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Unit tests (go test ./internal/controller/...) failed when run directly, even after the envtest binaries had been downloaded. Only make test worked.

Changes

internal/controller/suite_test.go

  • Read KUBEBUILDER_ASSETS first (set automatically by make test)
  • Fall back to absolute project-local bin/k8s/ path via os.Getwd()
  • Second fallback to envtest.SetupEnvtestDefaultBinaryAssetsDirectory() (system cache)
  • Extracted "1.31.0" into const envtestK8sVersion — single source of truth,
    cross-referenced to ENVTEST_K8S_VERSION in the Makefile

Makefile

  • Added comment on ENVTEST_K8S_VERSION pointing at suite_test.go to prevent
    silent version drift when upgrading Kubernetes

.github/workflows/pr-check.yaml

  • Added unit-test job (~1 min, no cluster, no Docker)
  • build-and-test (E2E, ~15 min) now depends on unit-test via needs:
    so cluster time is not spent on PRs with broken unit tests

test/Operator_tests.md

  • Documented the setup steps for running go test directly
  • Explained what make envtest installs vs what downloads the assets
  • Explained what KUBEBUILDER_ASSETS and 1.31.0 mean

How to verify

# One-time setup per clone
make envtest

# Direct go test — now works without any env var export
go test ./internal/controller/... -v

Summary by Sourcery

Ensure envtest-based Go unit tests run consistently both via make test and direct go test, and gate E2E CI runs on fast unit tests.

Bug Fixes:

  • Fix failure of controller unit tests when running go test directly by improving envtest binary discovery.

Enhancements:

  • Align envtest Kubernetes version configuration between Go tests, Makefile, and CI via a shared constant and comments.
  • Improve envtest binary lookup by preferring KUBEBUILDER_ASSETS, then local project cache, then the system cache.

CI:

  • Add a dedicated unit-test GitHub Actions job that installs envtest assets, runs Go unit tests with coverage, and uploads results.
  • Make the slower build-and-test (E2E) CI job depend on successful unit tests to avoid wasting cluster resources.

Documentation:

  • Expand operator testing documentation with detailed instructions for installing envtest, running unit tests directly with go test, and explaining KUBEBUILDER_ASSETS and the pinned Kubernetes version.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Assisted-by: Bob
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Assisted-by: Bob
@shreyabiradar07 shreyabiradar07 self-assigned this Jul 29, 2026
@sourcery-ai

sourcery-ai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

Updates envtest binary resolution to support running Go unit tests directly without make test, introduces a fast unit-test CI job, and documents envtest setup and versioning to keep Makefile, tests, and CI in sync.

Sequence diagram for envtest asset path resolution in suite_test.go

sequenceDiagram
    participant TestSuite
    participant Env as os
    participant Envtest as envtest

    TestSuite->>Env: Getenv KUBEBUILDER_ASSETS
    alt KUBEBUILDER_ASSETS is set
        Env-->>TestSuite: assetsPath
    else KUBEBUILDER_ASSETS is empty
        TestSuite->>Env: Getwd
        Env-->>TestSuite: projectRoot
        TestSuite-->>TestSuite: build bin/k8s path
        alt bin/k8s exists
            TestSuite-->>TestSuite: use local bin/k8s assets
        else bin/k8s missing
            TestSuite->>Envtest: SetupEnvtestDefaultBinaryAssetsDirectory
            Envtest-->>TestSuite: defaultAssetsPath
        end
    end
Loading

Flow diagram for updated CI unit-test and E2E jobs

flowchart LR
    gh[GitHub PR event]
    ut[Job unit-test
    go test ./internal/...]
    bt[Job build-and-test
    Kind cluster + E2E]

    gh --> ut
    ut --> bt
Loading

File-Level Changes

Change Details Files
Make envtest binary lookup work when running go test directly by supporting env var and fallback paths.
  • Introduce envtestK8sVersion constant as single source of truth for the envtest Kubernetes version.
  • Change BinaryAssetsDirectory to be computed from a new lookup order: KUBEBUILDER_ASSETS env var, then project-local bin/k8s/--, then controller-runtime envtest default cache dir.
  • Use os.Getwd and filepath joins to build the project-local bin/k8s path and only use it if it exists.
internal/controller/suite_test.go
Keep envtest Kubernetes version consistent across Makefile, tests, and CI.
  • Document that ENVTEST_K8S_VERSION must match envtestK8sVersion in suite_test.go.
  • Set ENVTEST_K8S_VERSION env var in the GitHub Actions workflow and pass it to setup-envtest.
  • Add comments in workflow and Makefile explaining the cross-file version coupling.
Makefile
.github/workflows/pr-check.yaml
Add a fast unit test gate in CI that runs before slower E2E tests.
  • Add unit-test job to pr-check workflow that installs setup-envtest, downloads envtest binaries, and runs go test ./internal/... with coverage.
  • Make existing build-and-test (E2E) job depend on unit-test via needs so E2E only runs if unit tests pass.
  • Upload unit test logs and coverage as artifacts for easier debugging.
.github/workflows/pr-check.yaml
Document how to install envtest and run unit tests directly with go test, including env var usage and version pinning.
  • Add detailed instructions for running unit tests with Option A (make test) and Option B (direct go test).
  • Explain what setup-envtest installs versus what downloads the actual Kubernetes binaries and how KUBEBUILDER_ASSETS is used.
  • Clarify what the pinned Kubernetes version (1.31.0) represents and how it must align with Makefile and suite_test.go, plus update examples and notes in the unit test section.
test/Operator_tests.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • In suite_test.go, BinaryAssetsDirectory is always set even if no suitable directory is found; consider only assigning this field when binaryAssetsDir is non-empty so that controller-runtime can still fall back to its built-in default behavior.
  • The Run unit tests step in pr-check.yaml uses nested double quotes inside the KUBEBUILDER_ASSETS="$(...)" assignment (specifically around --bin-dir "$(pwd)/bin"), which will break the shell; refactor the command to avoid conflicting quotes, e.g., by using single quotes for the outer string or separating the assignment into multiple lines.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `suite_test.go`, `BinaryAssetsDirectory` is always set even if no suitable directory is found; consider only assigning this field when `binaryAssetsDir` is non-empty so that controller-runtime can still fall back to its built-in default behavior.
- The `Run unit tests` step in `pr-check.yaml` uses nested double quotes inside the `KUBEBUILDER_ASSETS="$(...)"` assignment (specifically around `--bin-dir "$(pwd)/bin"`), which will break the shell; refactor the command to avoid conflicting quotes, e.g., by using single quotes for the outer string or separating the assignment into multiple lines.

## Individual Comments

### Comment 1
<location path=".github/workflows/pr-check.yaml" line_range="49" />
<code_context>
+
+      - name: Run unit tests
+        run: |
+          KUBEBUILDER_ASSETS="$(./bin/setup-envtest-release-0.19 use ${{ env.ENVTEST_K8S_VERSION }} --bin-dir "$(pwd)/bin" -p path)" \
+          go test ./internal/... -v -coverprofile=cover.out 2>&1 | tee /tmp/unit-test-output.log
+          exit ${PIPESTATUS[0]}
</code_context>
<issue_to_address>
**issue (bug_risk):** Fix nested quoting in KUBEBUILDER_ASSETS assignment to avoid shell syntax errors.

As written, the nested double quotes around `"$(pwd)/bin"` terminate the outer double-quoted string, so bash will treat the `KUBEBUILDER_ASSETS=...` assignment as a syntax error.

You can fix this by either escaping the inner quotes:

```yaml
run: |
  KUBEBUILDER_ASSETS="$(./bin/setup-envtest-release-0.19 use ${{ env.ENVTEST_K8S_VERSION }} --bin-dir \"$(pwd)/bin\" -p path)" \
  go test ./internal/... -v -coverprofile=cover.out 2>&1 | tee /tmp/unit-test-output.log
  exit ${PIPESTATUS[0]}
```

or by avoiding nested quotes via an intermediate variable:

```yaml
run: |
  BIN_DIR="$(pwd)/bin"
  KUBEBUILDER_ASSETS="$(./bin/setup-envtest-release-0.19 use ${{ env.ENVTEST_K8S_VERSION }} --bin-dir "$BIN_DIR" -p path)" \
  go test ./internal/... -v -coverprofile=cover.out 2>&1 | tee /tmp/unit-test-output.log
  exit ${PIPESTATUS[0]}
```
</issue_to_address>

### Comment 2
<location path=".github/workflows/pr-check.yaml" line_range="42-44" />
<code_context>
+      - name: Install setup-envtest
+        run: make envtest
+
+      - name: Download envtest binaries
+        run: |
+          ./bin/setup-envtest-release-0.19 use ${{ env.ENVTEST_K8S_VERSION }} \
+            --bin-dir "$(pwd)/bin"
+
</code_context>
<issue_to_address>
**suggestion (performance):** Avoid running `setup-envtest` twice to reduce redundant work in CI.

`setup-envtest` is currently run once in "Download envtest binaries" and again when setting `KUBEBUILDER_ASSETS`, causing duplicate downloads/path resolution each run and increasing CI time and potential flakiness.

Consider either:
- Using `-p path` in the first call, persisting the resolved path (file/env var) and reusing it in the test step, or
- Removing the first step and relying on the `KUBEBUILDER_ASSETS` assignment (with `use ... -p path`) to both download and resolve the path.

This avoids redundant external calls and keeps the workflow simpler.

Suggested implementation:

```
      - name: Install dependencies
        run: go mod download && go mod verify


env:

```

To fully implement your comment, you should:
1. Update the step where `KUBEBUILDER_ASSETS` is set (likely the test step) to call `setup-envtest-release-0.19 use ${{ env.ENVTEST_K8S_VERSION }} -p path` and export `KUBEBUILDER_ASSETS` using that resolved path (or a persisted file).
2. Ensure that this single `use ... -p path` call both downloads the envtest binaries and sets the path used by the tests, so no separate `make envtest` step is required elsewhere.
</issue_to_address>

### Comment 3
<location path="internal/controller/suite_test.go" line_range="76-84" />
<code_context>

 	By("bootstrapping test environment")
+
+	// Lookup order: KUBEBUILDER_ASSETS env var → project-local bin/k8s/ → setup-envtest system cache.
+	binaryAssetsDir := os.Getenv("KUBEBUILDER_ASSETS")
+	if binaryAssetsDir == "" {
+		pkgDir, err := os.Getwd()
+		Expect(err).NotTo(HaveOccurred(), "could not determine working directory")
+		localDir := filepath.Join(pkgDir, "..", "..", "bin", "k8s",
+			fmt.Sprintf("%s-%s-%s", envtestK8sVersion, runtime.GOOS, runtime.GOARCH))
+		if _, err := os.Stat(localDir); err == nil {
+			binaryAssetsDir = localDir
+		}
+	}
+	if binaryAssetsDir == "" {
+		systemDir, err := envtest.SetupEnvtestDefaultBinaryAssetsDirectory()
</code_context>
<issue_to_address>
**suggestion (testing):** Consider failing fast (or asserting) when no BinaryAssetsDirectory is resolved to avoid flaky or environment-dependent test behavior.

If none of KUBEBUILDER_ASSETS, the project-local bin/k8s path, or the envtest system cache resolve to a directory, `binaryAssetsDir` stays empty and envtest falls back to controller-runtime defaults. That can silently use an unexpected Kubernetes version or fail later with a vague error. Consider adding a final `Expect(binaryAssetsDir).NotTo(BeEmpty(), ...)` with a clear message (e.g. to run `make envtest` or set `KUBEBUILDER_ASSETS`). Also, if `envtest.SetupEnvtestDefaultBinaryAssetsDirectory()` returns an error, surfacing it instead of ignoring it would make missing binaries easier to diagnose.

```suggestion
	if binaryAssetsDir == "" {
		systemDir, err := envtest.SetupEnvtestDefaultBinaryAssetsDirectory()
		Expect(err).NotTo(HaveOccurred(),
			"failed to resolve envtest binary assets directory from system cache; "+
				"ensure envtest binaries for Kubernetes %s are installed (e.g. via `make envtest`) or set KUBEBUILDER_ASSETS",
			envtestK8sVersion)

		binaryAssetsDir = filepath.Join(systemDir,
			fmt.Sprintf("%s-%s-%s", envtestK8sVersion, runtime.GOOS, runtime.GOARCH))
	}

	Expect(binaryAssetsDir).NotTo(BeEmpty(),
		"failed to resolve envtest binary assets directory; "+
			"set KUBEBUILDER_ASSETS or run `make envtest` to download envtest binaries for Kubernetes %s",
		envtestK8sVersion)

	testEnv = &envtest.Environment{
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread .github/workflows/pr-check.yaml Outdated
Comment thread .github/workflows/pr-check.yaml Outdated
Comment thread internal/controller/suite_test.go
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Assisted-by: Bob
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Assisted-by: Bob
…r.go

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Assisted-by: Bob
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Assisted-by: Bob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd test Test changes

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant