Skip to content

Conversation

@tenfyzhong
Copy link
Collaborator

@tenfyzhong tenfyzhong commented Jan 29, 2026

What problem does this PR solve?

Issue Number: close #4089

The make unit_test_in_verify_ci target exits with code 1 even when all tests pass, because coverage is applied to packages without tests and triggers covdata errors.

What is changed and how it works?

  • Extract the package exclusion regex into PACKAGE_EXCLUDE.
  • Split packages into ones with tests vs. without tests using go list and build tags.
  • Run coverage only on packages containing tests, and run the rest without coverage.
  • Apply the split logic to unit_test, unit_test_in_verify_ci, and unit_test_in_verify_ci_next_gen.

Check List

Tests

  • Unit test (make unit_test_in_verify_ci)

Questions

Will it cause performance regression or break compatibility?

No.

Do you need to update user documentation, design documentation or monitoring documentation?

No.

Release note

None

Summary by CodeRabbit

  • Chores

    • Improved build system efficiency through optimized package listing and test execution workflow.
  • Tests

    • Enhanced unit test infrastructure with refined execution phases and coverage handling.

Note: This release contains internal build and testing infrastructure improvements with no user-facing changes.

✏️ Tip: You can customize this high-level summary in your review settings.

- Extract package exclusion pattern into reusable variable `PACKAGE_EXCLUDE`
- Modify `unit_test`, `unit_test_in_verify_ci`, and `unit_test_in_verify_ci_next_gen` targets to split packages into those with test files and those without
- Run coverage tests only on packages containing test files to avoid errors
- Execute non-test packages separately without coverage flags to ensure all packages are tested appropriately

Signed-off-by: tenfyzhong <tenfy@tenfy.cn>
@ti-chi-bot ti-chi-bot bot added the release-note-none Denotes a PR that doesn't merit a release note. label Jan 29, 2026
@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 29, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign asddongmen for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@gemini-code-assist
Copy link

Summary of Changes

Hello @tenfyzhong, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a recurring issue in the CI pipeline where unit test targets would erroneously fail when attempting to generate code coverage for Go packages that do not contain any test files. By introducing a mechanism to differentiate between packages with and without tests, the build system now intelligently applies coverage only where appropriate, ensuring that all unit test targets complete successfully and provide meaningful coverage metrics without encountering covdata errors.

Highlights

  • Problem Resolution: Addresses and closes issue [Bug] unit_test_in_verify_ci exits 1 with failing tests #4089, which caused the make unit_test_in_verify_ci_next_gen target to fail due to coverage being applied to packages without tests.
  • Code Refactoring: The package exclusion regex has been extracted into a new PACKAGE_EXCLUDE variable for improved maintainability and reusability.
  • Intelligent Test Execution: Implemented logic to dynamically split Go packages into two groups: those containing tests and those without, utilizing go list and build tags.
  • Optimized Coverage Reporting: Coverage is now exclusively applied to packages that contain tests, preventing covdata errors and ensuring accurate reporting. Packages without tests are run without coverage.
  • Target Scope: The new test execution logic has been applied to the unit_test, unit_test_in_verify_ci, and unit_test_in_verify_ci_next_gen Makefile targets.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ti-chi-bot ti-chi-bot bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Jan 29, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request addresses an issue where the test process would fail due to coverage being applied to packages without tests. The fix involves separating packages with tests from those without, and only applying coverage to the former. This is a good solution to the problem.

My review focuses on improving the maintainability of the Makefile. I've noticed significant code duplication across several test targets. I've left a comment with a suggestion to refactor this using a define block, which would make future changes easier. I've also suggested a small improvement to the go list command to make it cleaner.

Comment on lines +251 to +252
test_pkgs=$$($(GO) list -tags="$(TEST_FLAG)" -f '{{if or .TestGoFiles .XTestGoFiles}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
no_test_pkgs=$$($(GO) list -tags="$(TEST_FLAG)" -f '{{if not (or .TestGoFiles .XTestGoFiles)}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \

Choose a reason for hiding this comment

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

medium

This logic to separate packages based on the presence of test files is duplicated in the unit_test, unit_test_in_verify_ci, and unit_test_in_verify_ci_next_gen targets. This duplication can make the Makefile difficult to maintain.

Consider refactoring this repeated logic into a define block to improve maintainability.

Additionally, you can simplify the go list command by using a format string that produces newline-separated output, which eliminates the need for tr.

test_pkgs=$$($(GO) list -tags="$(TEST_FLAG)" -f '{{if or .TestGoFiles .XTestGoFiles}}{{.ImportPath}}{{"\n"}}{{end}}' ./... | grep -vE '$(PACKAGE_EXCLUDE)'); \
	no_test_pkgs=$$($(GO) list -tags="$(TEST_FLAG)" -f '{{if not (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{"\n"}}{{end}}' ./... | grep -vE '$(PACKAGE_EXCLUDE)'); \

@coderabbitai
Copy link

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

The Makefile introduces a centralized PACKAGE_EXCLUDE variable and refactors unit test execution by splitting packages into two groups: those with tests (run with coverage) and those without (run without coverage), with explicit error handling preserved.

Changes

Cohort / File(s) Summary
Makefile Test Execution Refactoring
Makefile
Introduces PACKAGE_EXCLUDE centralization, reworks unit_test, unit_test_in_verify_ci, and unit_test_in_verify_ci_next_gen targets to compute test_pkgs and no_test_pkgs via go list with tagging, splitting execution into two phases (with/without coverage) while maintaining error handling and failpoint cleanup.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Two paths diverge in a Makefile deep,
One runs with coverage, one sans the sweep,
Packages sorted with tags so bright,
Error handling preserved, all tests run right,
Finally the exit code shows the truth! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: avoiding coverage for packages without tests, which directly addresses the issue.
Linked Issues check ✅ Passed The changes directly address issue #4089 by splitting test packages and applying coverage only where tests exist, preventing the covdata errors causing the non-zero exit.
Out of Scope Changes check ✅ Passed All changes in the Makefile are directly related to fixing the unit test verification targets and refactoring package exclusion logic as required by issue #4089.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The pull request description follows the required template with all critical sections completed: issue reference, problem statement, changes explained, test verification, and release notes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@Makefile`:
- Around line 289-303: The Makefile runs tools/bin/gocov convert on
"$(TEST_DIR)/cov.unit.out" even when no tests ran; guard that step by checking
the existence and non-zero size of the coverage file (cov.unit.out) before
invoking tools/bin/gocov convert and tools/bin/gocov-xml. Modify the block that
defines test_pkgs/no_test_pkgs (and the final conversion lines) to only run the
convert/ XML generation when "$(TEST_DIR)/cov.unit.out" exists and is non-empty
(or equivalently only when test_pkgs is non-empty), while preserving the
existing FAILPOINT_DISABLE invocation.
- Around line 268-281: The Makefile step assumes "$(TEST_DIR)/cov.unit.out"
exists but if test_pkgs is empty no coverage file is created; modify the target
to guard the gocov conversion by checking for the existence and non-zero size of
"$(TEST_DIR)/cov.unit.out" (or create an empty fallback file) before running
tools/bin/gocov convert and tools/bin/gocov-xml, using the existing variables
TEST_DIR and cov.unit.out and keeping the current behavior when tests produce
coverage; ensure this check occurs after the test_pkgs/no_test_pkgs blocks that
create the file.
🧹 Nitpick comments (1)
Makefile (1)

251-260: Consider removing the no_test_pkgs execution block.

Running go test on packages without test files is redundant—it only outputs [no test files] and exits successfully. While harmless, it adds execution time without providing value.

If the intent is to verify compilation with test build tags, this is already achieved when building the test binary or during CI builds.

♻️ Proposed simplification (optional)
 	test_pkgs=$$($(GO) list -tags="$(TEST_FLAG)" -f '{{if or .TestGoFiles .XTestGoFiles}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
-	no_test_pkgs=$$($(GO) list -tags="$(TEST_FLAG)" -f '{{if not (or .TestGoFiles .XTestGoFiles)}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
 	if [ -n "$$test_pkgs" ]; then \
 		$(GOTEST) -cover -covermode=atomic -coverprofile="$(TEST_DIR)/cov.unit.out" $$test_pkgs \
 		|| { $(FAILPOINT_DISABLE); exit 1; }; \
-	fi; \
-	if [ -n "$$no_test_pkgs" ]; then \
-		$(GOTEST) $$no_test_pkgs \
-		|| { $(FAILPOINT_DISABLE); exit 1; }; \
 	fi

Comment on lines +268 to 281
test_pkgs=$$($(GO) list -tags="intest" -f '{{if or .TestGoFiles .XTestGoFiles}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
no_test_pkgs=$$($(GO) list -tags="intest" -f '{{if not (or .TestGoFiles .XTestGoFiles)}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
if [ -n "$$test_pkgs" ]; then \
CGO_ENABLED=1 tools/bin/gotestsum --junitfile cdc-junit-report.xml -- -v -timeout 300s -p $(P) --race --tags=intest \
-parallel=16 \
-covermode=atomic -coverprofile="$(TEST_DIR)/cov.unit.out" $$test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi; \
if [ -n "$$no_test_pkgs" ]; then \
CGO_ENABLED=1 $(GO) test -v -timeout 300s -p $(P) --race --tags=intest \
-parallel=16 $$no_test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi
tools/bin/gocov convert "$(TEST_DIR)/cov.unit.out" | tools/bin/gocov-xml > cdc-coverage.xml
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

Potential edge case: coverage file may not exist if no packages have tests.

If test_pkgs is empty (unlikely but possible), cov.unit.out won't be generated, and line 281 will fail when gocov convert attempts to read it.

Consider adding a guard or touching an empty coverage file as a fallback.

🛡️ Proposed defensive fix
 	if [ -n "$$no_test_pkgs" ]; then \
 		CGO_ENABLED=1 $(GO) test -v -timeout 300s -p $(P) --race --tags=intest \
 		-parallel=16 $$no_test_pkgs \
 		|| { $(FAILPOINT_DISABLE); exit 1; }; \
 	fi
+	`@if` [ ! -f "$(TEST_DIR)/cov.unit.out" ]; then \
+		echo "mode: atomic" > "$(TEST_DIR)/cov.unit.out"; \
+	fi
 	tools/bin/gocov convert "$(TEST_DIR)/cov.unit.out" | tools/bin/gocov-xml > cdc-coverage.xml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test_pkgs=$$($(GO) list -tags="intest" -f '{{if or .TestGoFiles .XTestGoFiles}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
no_test_pkgs=$$($(GO) list -tags="intest" -f '{{if not (or .TestGoFiles .XTestGoFiles)}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
if [ -n "$$test_pkgs" ]; then \
CGO_ENABLED=1 tools/bin/gotestsum --junitfile cdc-junit-report.xml -- -v -timeout 300s -p $(P) --race --tags=intest \
-parallel=16 \
-covermode=atomic -coverprofile="$(TEST_DIR)/cov.unit.out" $$test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi; \
if [ -n "$$no_test_pkgs" ]; then \
CGO_ENABLED=1 $(GO) test -v -timeout 300s -p $(P) --race --tags=intest \
-parallel=16 $$no_test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi
tools/bin/gocov convert "$(TEST_DIR)/cov.unit.out" | tools/bin/gocov-xml > cdc-coverage.xml
test_pkgs=$$($(GO) list -tags="intest" -f '{{if or .TestGoFiles .XTestGoFiles}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
no_test_pkgs=$$($(GO) list -tags="intest" -f '{{if not (or .TestGoFiles .XTestGoFiles)}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
if [ -n "$$test_pkgs" ]; then \
CGO_ENABLED=1 tools/bin/gotestsum --junitfile cdc-junit-report.xml -- -v -timeout 300s -p $(P) --race --tags=intest \
-parallel=16 \
-covermode=atomic -coverprofile="$(TEST_DIR)/cov.unit.out" $$test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi; \
if [ -n "$$no_test_pkgs" ]; then \
CGO_ENABLED=1 $(GO) test -v -timeout 300s -p $(P) --race --tags=intest \
-parallel=16 $$no_test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi
`@if` [ ! -f "$(TEST_DIR)/cov.unit.out" ]; then \
echo "mode: atomic" > "$(TEST_DIR)/cov.unit.out"; \
fi
tools/bin/gocov convert "$(TEST_DIR)/cov.unit.out" | tools/bin/gocov-xml > cdc-coverage.xml
🤖 Prompt for AI Agents
In `@Makefile` around lines 268 - 281, The Makefile step assumes
"$(TEST_DIR)/cov.unit.out" exists but if test_pkgs is empty no coverage file is
created; modify the target to guard the gocov conversion by checking for the
existence and non-zero size of "$(TEST_DIR)/cov.unit.out" (or create an empty
fallback file) before running tools/bin/gocov convert and tools/bin/gocov-xml,
using the existing variables TEST_DIR and cov.unit.out and keeping the current
behavior when tests produce coverage; ensure this check occurs after the
test_pkgs/no_test_pkgs blocks that create the file.

Comment on lines +289 to 303
test_pkgs=$$($(GO) list -tags="intest,nextgen" -f '{{if or .TestGoFiles .XTestGoFiles}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
no_test_pkgs=$$($(GO) list -tags="intest,nextgen" -f '{{if not (or .TestGoFiles .XTestGoFiles)}} {{.ImportPath}} {{end}}' ./... | tr -s ' ' '\n' | grep -vE '$(PACKAGE_EXCLUDE)'); \
if [ -n "$$test_pkgs" ]; then \
CGO_ENABLED=1 tools/bin/gotestsum --junitfile cdc-junit-report.xml -- -v -timeout 300s -p $(P) --race --tags=intest,nextgen \
-parallel=16 \
-covermode=atomic -coverprofile="$(TEST_DIR)/cov.unit.out" $$test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi; \
if [ -n "$$no_test_pkgs" ]; then \
CGO_ENABLED=1 $(GO) test -v -timeout 300s -p $(P) --race --tags=intest,nextgen \
-parallel=16 $$no_test_pkgs \
|| { $(FAILPOINT_DISABLE); exit 1; }; \
fi
tools/bin/gocov convert "$(TEST_DIR)/cov.unit.out" | tools/bin/gocov-xml > cdc-coverage.xml
$(FAILPOINT_DISABLE)
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

Same edge case concern as unit_test_in_verify_ci.

The coverage file guard suggestion from the previous comment applies here as well—if test_pkgs is empty, gocov convert on line 302 would fail.

Otherwise, the implementation correctly mirrors the other test targets with the appropriate intest,nextgen tags.

🤖 Prompt for AI Agents
In `@Makefile` around lines 289 - 303, The Makefile runs tools/bin/gocov convert
on "$(TEST_DIR)/cov.unit.out" even when no tests ran; guard that step by
checking the existence and non-zero size of the coverage file (cov.unit.out)
before invoking tools/bin/gocov convert and tools/bin/gocov-xml. Modify the
block that defines test_pkgs/no_test_pkgs (and the final conversion lines) to
only run the convert/ XML generation when "$(TEST_DIR)/cov.unit.out" exists and
is non-empty (or equivalently only when test_pkgs is non-empty), while
preserving the existing FAILPOINT_DISABLE invocation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note-none Denotes a PR that doesn't merit a release note. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] unit_test_in_verify_ci exits 1 with failing tests

1 participant