Skip to content

tests: avoid test port conflicts#10963

Open
rleungx wants to merge 5 commits into
tikv:masterfrom
rleungx:fix-test-port-conflicts
Open

tests: avoid test port conflicts#10963
rleungx wants to merge 5 commits into
tikv:masterfrom
rleungx:fix-test-port-conflicts

Conversation

@rleungx

@rleungx rleungx commented Jul 1, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: None

Fix flaky test failures like:

listen tcp 127.0.0.1:<port>: bind: address already in use

One observed case was pull-unit-test-next-gen-2 for PR #10943, where TestCheckClusterID restarted an embedded etcd instance with cluster A's old listen URLs after another test cluster had already been started. More generally, several MCS integration helpers allocated a free port with tempurl.Alloc() and only bound it later, leaving a TOCTOU window.

What is changed and how does it work?

tests: avoid test port conflicts

Avoid restarting TestCheckClusterID with cluster A's old listen URLs. The
test now captures cluster A's etcd cluster ID while it is running and
checks that ID against cluster B's peer URLs.

Allow MCS BaseServer to listen on http://127.0.0.1:0 and expose the
actual bound listen address. Initialize MCS listeners before service
registration, then register the actual advertise address and server name.

Make MCS test helpers default to http://127.0.0.1:0 for new test servers,
while preserving explicit listen addresses for tests that intentionally
restart on a fixed address.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)

Code changes

  • None

Side effects

  • None

Related changes

  • None

Test details:

  • go test ./tests/server -run '^TestCheckClusterID$' -count=1
  • go test ./pkg/mcs/server ./pkg/mcs/tso/server ./pkg/mcs/scheduling/server ./pkg/mcs/router/server
  • cd tests/integrations && go test ./mcs/router ./mcs/tso ./mcs/members ./mcs/discovery ./mcs/keyspace ./mcs/resourcemanager ./tso -run '^$'
  • cd tests/integrations && go test ./mcs/resourcemanager -run '^TestResourceManagerServer$' -count=1
  • cd tests/integrations && go test ./mcs/tso -run '^TestTSOServerTestSuite/TestTSOServerStartAndStopNormally$' -count=1

Note: go test ./pkg/mcs/resourcemanager/server -run '^TestCleanUpTicker$' -count=1 still fails locally with the existing stale-record count assertion; that failure is unrelated to this port-conflict change.

Release note

None.

Summary by CodeRabbit

  • Bug Fixes
    • Improved startup reliability by initializing listener/address configuration earlier and reconciling advertised addresses with the actual bound address (including consistent naming and advertise host derivation).
    • Added safer startup failure cleanup to deregister services and close listeners when startup fails.
    • Improved handling of kernel-selected ports so listen/advertise resolution remains consistent at runtime.
  • Tests
    • Added leak-checked unit tests covering actual listen address resolution, advertise resolution, and unspecified-address-family behavior.
  • Chores
    • Simplified integration test server startup by removing temp URL allocations and normalizing test listen addresses when empty.

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue dco-signoff: yes Indicates the PR's author has signed the dco. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Jul 1, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

[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 hundundm 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

@ti-chi-bot ti-chi-bot Bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jul 1, 2026
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rleungx, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f362346-a923-4331-9d9c-215d4ffffcc5

📥 Commits

Reviewing files that changed from the base of the PR and between 06d65bb and cac2301.

📒 Files selected for processing (6)
  • pkg/mcs/resourcemanager/server/listener_test.go
  • pkg/mcs/router/server/listener_test.go
  • pkg/mcs/scheduling/server/listener_test.go
  • pkg/mcs/server/server.go
  • pkg/mcs/tso/server/listener_test.go
  • tools/pd-ctl/tests/store/store_test.go
📝 Walkthrough

Walkthrough

This PR moves MCS listener initialization earlier, records resolved bound addresses, updates advertise/name config from those values, normalizes empty test listen inputs, replaces temp URL allocation in integration tests, and refactors one cluster-ID test.

Changes

Core server changes

Layer / File(s) Summary
BaseServer listener tracking and address resolution
pkg/mcs/server/server.go, pkg/mcs/server/server_test.go
Adds actual listen address tracking, resolver helpers for listen/advertise addresses, and tests for kernel-selected ports and address resolution.
Service startup wiring
pkg/mcs/resourcemanager/server/server.go, pkg/mcs/router/server/server.go, pkg/mcs/scheduling/server/server.go, pkg/mcs/tso/server/server.go
Moves listener initialization into Run, adds error-path cleanup, and removes inline listener setup from startServer; TSO also parses the advertise host from the resolved address.
Test listen address normalization
tests/testutil.go
Adds a default MCS test listen address and normalizes empty listen-address inputs for single-server test helpers.
Integration tests stop allocating temp URLs
tests/integrations/mcs/discovery/register_test.go, tests/integrations/mcs/keyspace/tso_keyspace_group_test.go, tests/integrations/mcs/members/member_test.go, tests/integrations/mcs/resourcemanager/*, tests/integrations/mcs/router/server_test.go, tests/integrations/mcs/tso/server_test.go, tests/integrations/tso/*
Replaces tempurl.Alloc() with empty-string arguments and removes unused tempurl imports across affected test cases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Cluster ID check test refactor

Layer / File(s) Summary
TestCheckClusterID refactor
tests/server/server_test.go
Removes the embedded etcd dependency, derives the source cluster ID from the running leader, and asserts the specific mismatch error text.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • tikv/pd#10600: Shares the TSO advertise-host derivation path that is updated here in pkg/mcs/tso/server/server.go.

Suggested reviewers: okJiang, lhy1024, bufferflies

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description mostly matches the template, but it lacks the required linked issue number. Replace Issue Number: None with a linked issue line such as Issue Number: Close #1234``, and keep the existing sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: avoiding test port conflicts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@rleungx rleungx force-pushed the fix-test-port-conflicts branch from e274147 to 45eba90 Compare July 1, 2026 07:42
@ti-chi-bot ti-chi-bot Bot added release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/needs-triage-completed and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. do-not-merge/needs-triage-completed labels Jul 1, 2026
@rleungx rleungx force-pushed the fix-test-port-conflicts branch from 45eba90 to 2bd14ff Compare July 1, 2026 07:47

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/mcs/server/server.go`:
- Around line 212-226: In buildActualListenAddr, the unspecified-host
normalization currently hardcodes 127.0.0.1 for both IPv4 and IPv6, which
changes the address family; update the host handling so
net.ParseIP(host).IsUnspecified() preserves the original family by mapping IPv6
unspecified addresses to ::1 and IPv4 unspecified addresses to 127.0.0.1. Keep
the fix localized to buildActualListenAddr and verify
GetActualListenAddr/ResolveAdvertiseListenAddr continue to return a reachable
URL when listenURL.Host or addr.String() comes from an IPv6 bind.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9ce468be-3371-42c2-af62-555a8368b02b

📥 Commits

Reviewing files that changed from the base of the PR and between 5c811b2 and 45eba90.

📒 Files selected for processing (18)
  • pkg/mcs/resourcemanager/server/server.go
  • pkg/mcs/router/server/server.go
  • pkg/mcs/scheduling/server/server.go
  • pkg/mcs/server/server.go
  • pkg/mcs/server/server_test.go
  • pkg/mcs/tso/server/server.go
  • tests/integrations/mcs/discovery/register_test.go
  • tests/integrations/mcs/keyspace/tso_keyspace_group_test.go
  • tests/integrations/mcs/members/member_test.go
  • tests/integrations/mcs/resourcemanager/resource_manager_test.go
  • tests/integrations/mcs/resourcemanager/server_test.go
  • tests/integrations/mcs/router/server_test.go
  • tests/integrations/mcs/tso/server_test.go
  • tests/integrations/tso/client_test.go
  • tests/integrations/tso/consistency_test.go
  • tests/integrations/tso/server_test.go
  • tests/server/server_test.go
  • tests/testutil.go

Comment thread pkg/mcs/server/server.go
@rleungx rleungx force-pushed the fix-test-port-conflicts branch from 2bd14ff to 9dfb8d8 Compare July 1, 2026 08:04
@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 58.97436% with 64 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.23%. Comparing base (5c811b2) to head (cac2301).
⚠️ Report is 13 commits behind head on master.

❌ Your patch check has failed because the patch coverage (58.97%) is below the target coverage (74.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10963      +/-   ##
==========================================
+ Coverage   79.20%   79.23%   +0.02%     
==========================================
  Files         541      541              
  Lines       75450    75818     +368     
==========================================
+ Hits        59762    60073     +311     
- Misses      11456    11490      +34     
- Partials     4232     4255      +23     
Flag Coverage Δ
unittests 79.23% <58.97%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx rleungx force-pushed the fix-test-port-conflicts branch from 9dfb8d8 to 9f82f85 Compare July 1, 2026 09:24

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/mcs/server/server_test.go (1)

33-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ignored error from Close().

svr.GetListener().Close() return value is discarded. As per coding guidelines, **/*.go: "No ignored errors unless allowed in .golangci.yml errcheck exclusions." Test cleanup errors are usually low-risk, but consider asserting via require.NoError.

🔧 Proposed fix
-	defer svr.GetListener().Close()
+	defer func() {
+		re.NoError(svr.GetListener().Close())
+	}()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/mcs/server/server_test.go` around lines 33 - 46, The test cleanup in
TestInitListenerWithKernelSelectedPort is ignoring the error returned by
GetListener().Close(). Update the deferred close on the listener to check the
returned error with require.NoError so the cleanup path follows the
error-handling rules; use the existing svr and GetListener() call site to locate
the fix.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/mcs/scheduling/server/server.go`:
- Around line 166-168: The startup cleanup path in server.go ignores the result
of closing the listener, which can hide resource cleanup failures and violate
errcheck rules. In the listener cleanup block around s.GetListener(), capture
the Close() return value, check it, and log or otherwise handle any close error
instead of discarding it; keep the fix localized to the startup error path in
the server setup logic.

In `@pkg/mcs/tso/server/server.go`:
- Around line 177-179: The cleanup path around s.GetListener() is ignoring the
error returned by Close(), which violates the errcheck/resource-cleanup rule.
Update the listener shutdown logic in the server startup/cleanup flow to capture
and handle the Close() result instead of discarding it, and log the failure with
enough context when err is already set. Use the existing s.GetListener() access
pattern and the surrounding err != nil branch to locate the fix.

---

Nitpick comments:
In `@pkg/mcs/server/server_test.go`:
- Around line 33-46: The test cleanup in TestInitListenerWithKernelSelectedPort
is ignoring the error returned by GetListener().Close(). Update the deferred
close on the listener to check the returned error with require.NoError so the
cleanup path follows the error-handling rules; use the existing svr and
GetListener() call site to locate the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89b113cb-852f-4eaf-83e0-e3b3200a86dd

📥 Commits

Reviewing files that changed from the base of the PR and between 45eba90 and 9f82f85.

📒 Files selected for processing (18)
  • pkg/mcs/resourcemanager/server/server.go
  • pkg/mcs/router/server/server.go
  • pkg/mcs/scheduling/server/server.go
  • pkg/mcs/server/server.go
  • pkg/mcs/server/server_test.go
  • pkg/mcs/tso/server/server.go
  • tests/integrations/mcs/discovery/register_test.go
  • tests/integrations/mcs/keyspace/tso_keyspace_group_test.go
  • tests/integrations/mcs/members/member_test.go
  • tests/integrations/mcs/resourcemanager/resource_manager_test.go
  • tests/integrations/mcs/resourcemanager/server_test.go
  • tests/integrations/mcs/router/server_test.go
  • tests/integrations/mcs/tso/server_test.go
  • tests/integrations/tso/client_test.go
  • tests/integrations/tso/consistency_test.go
  • tests/integrations/tso/server_test.go
  • tests/server/server_test.go
  • tests/testutil.go
🚧 Files skipped from review as they are similar to previous changes (14)
  • tests/integrations/mcs/resourcemanager/server_test.go
  • tests/integrations/mcs/router/server_test.go
  • tests/integrations/mcs/resourcemanager/resource_manager_test.go
  • tests/integrations/tso/server_test.go
  • tests/integrations/mcs/discovery/register_test.go
  • tests/integrations/tso/consistency_test.go
  • tests/integrations/mcs/members/member_test.go
  • tests/testutil.go
  • tests/server/server_test.go
  • tests/integrations/tso/client_test.go
  • tests/integrations/mcs/keyspace/tso_keyspace_group_test.go
  • pkg/mcs/router/server/server.go
  • pkg/mcs/resourcemanager/server/server.go
  • pkg/mcs/server/server.go

Comment thread pkg/mcs/scheduling/server/server.go
Comment thread pkg/mcs/tso/server/server.go
@rleungx

rleungx commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

/retest

Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx rleungx force-pushed the fix-test-port-conflicts branch from 0abf888 to 2552141 Compare July 2, 2026 09:33
Comment thread pkg/mcs/server/server.go

// ResolveAdvertiseListenAddr returns actualListenAddr when advertiseAddr was left
// unspecified or still points at a kernel-selected port.
func ResolveAdvertiseListenAddr(advertiseAddr, actualListenAddr string) string {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When advertiseAddr uses port 0, this currently returns actualListenAddr directly, which drops the explicitly configured advertise host.

For example, with listen-addr=http://127.0.0.1:0 and advertise-listen-addr=http://10.0.0.5:0, the registered address becomes http://127.0.0.1:<port> instead of the expected http://10.0.0.5:<port>. That can publish an incorrect service discovery endpoint.

I think we should only use the full actual listen address when advertiseAddr == "". If advertise only has a zero port, preserve its scheme/host and replace only the port with the listener actual bound port.

A small unit test can cover this case:

require.Equal(t,
    "http://10.0.0.5:12345",
    ResolveAdvertiseListenAddr("http://10.0.0.5:0", "http://127.0.0.1:12345"))

@lhy1024

lhy1024 commented Jul 2, 2026

Copy link
Copy Markdown
Member

There is still an uncovered port-allocation path in the test helpers. This PR moves the single-server helpers to the :0 dynamic binding path, but the cluster helpers still pre-allocate ports through tempurl.Alloc():

  • tests/tso_cluster.go
  • tests/scheduling_cluster.go
  • tests/resource_manager_cluster.go

These helpers close the temporary listener and later bind the real server to the same port, so they keep the same TOCTOU port-conflict window. They are used by many integration tests via NewTestTSOCluster, NewTestSchedulingCluster, and NewTestResourceManagerCluster, so the "avoid test port conflicts" fix is incomplete.

Please consider moving these cluster helpers to the same :0 dynamic binding path, then store the server and cleanup function using the resolved actual address after startup.

rleungx added 2 commits July 3, 2026 10:40
Signed-off-by: Ryan Leung <rleungx@gmail.com>
Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx rleungx force-pushed the fix-test-port-conflicts branch from b0dfa3b to d08263d Compare July 6, 2026 09:11
Signed-off-by: Ryan Leung <rleungx@gmail.com>
@ti-chi-bot

ti-chi-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

[FORMAT CHECKER NOTIFICATION]

Notice: To remove the do-not-merge/needs-linked-issue label, please provide the linked issue number on one line in the PR body, for example: Issue Number: close #123 or Issue Number: ref #456, multiple issues should use full syntax for each issue and be separated by a comma, like: Issue Number: close #123, ref #456.

📖 For more info, you can check the "Linking issues" section in the CONTRIBUTING.md.

@ti-chi-bot ti-chi-bot Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jul 6, 2026
@rleungx

rleungx commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

/retest

@ti-chi-bot

ti-chi-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@rleungx: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-unit-test-next-gen-2 cac2301 link true /test pull-unit-test-next-gen-2

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Labels

dco-signoff: yes Indicates the PR's author has signed the dco. do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants