Skip to content

test: isolate unit tests from user state#1883

Open
luozhixiong01 wants to merge 6 commits into
mainfrom
fix/isolate-live-skills-tests
Open

test: isolate unit tests from user state#1883
luozhixiong01 wants to merge 6 commits into
mainfrom
fix/isolate-live-skills-tests

Conversation

@luozhixiong01

@luozhixiong01 luozhixiong01 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Default unit tests contained several side effects that depended on or modified developer state: two opt-in-worthy skills integration tests invoked the real npx skills CLI, ordinary update tests could fall through to npx, multiple packages wrote lark-cli cache/log/event state, registry users started background remote-metadata refreshes, and one API test saved a binary into the repository working directory.

Changes

  • Gate the two live skills integration tests behind LARKSUITE_CLI_RUN_LIVE_SKILLS_TESTS=1 and redirect all relevant user and agent directories to a temporary root.
  • Add make live-skills-test as the documented explicit entrypoint.
  • Fully mock skills discovery and sync in ordinary cmd/update tests so they cannot invoke npx.
  • Isolate config, data, log, and event state for packages that intentionally exercise those write paths.
  • Disable remote metadata refresh in unit-test packages that only exercise embedded registry/catalog behavior.
  • Run the binary auto-save API test from a temporary working directory.

Validation

  • make unit-test with an isolated HOME and blocked network: passed.
  • Dynamic default-test scan across 116 cmd, internal, shortcuts, and extension packages: passed.
  • Asserted no .lark-cli, .agents, .npm, or .claude state remained under the isolated HOME.
  • Asserted cmd/api/download.bin was not created in the repository.
  • Default cmd/update runtime dropped from about 80 seconds with real npx fallthrough to about 2 seconds with mocks.
  • make -n live-skills-test: passed.

The branch is rebased on current origin/main at 1c36744.

Summary by CodeRabbit

  • Tests
    • Added opt-in live skills integration tests with an isolated harness and shared seeding for real installs/lists, including longer execution windows.
    • Improved test isolation across suites with temporary config/log directories and deterministic registry seeding.
    • Strengthened API binary auto-save validations and updated skills-sync stubs for consistency.
    • Enhanced startup-brand integration tests using nonce-based helper selection.
  • Documentation
    • Updated build/test instructions to include make live-skills-test.
  • Chores
    • Added live-skills-test Makefile target to run the selected live tests with the opt-in flag.

@github-actions github-actions Bot added the size/S Low-risk docs, CI, test, or chore only changes label Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Live skills tests now use explicit opt-in gating, isolated temporary environments, shared seeding, and a dedicated Make target. Test packages gain isolated configuration and registry fixtures, while integration tests strengthen filesystem, startup, and strict-mode validation.

Changes

Test isolation and integration harnesses

Layer / File(s) Summary
Deterministic registry fixture harness
internal/registry/registrytest/*, cmd/testmain_test.go, cmd/auth/testmain_test.go, cmd/service/testmain_test.go
Adds embedded registry metadata, cache seeding, path validation, fixture contract tests, and package startup initialization.
Package filesystem isolation
cmd/*/testmain_test.go, internal/*/testmain_test.go
Redirects test configuration, data, and log directories to temporary locations and disables remote metadata where required.
Update synchronization test control
cmd/update/update_test.go
Adds mocked skills dependencies, isolated manual tests, index-fetch stubs, and shared opt-in preparation and seeding for live skills synchronization.
Integration test execution hardening
cmd/api/api_test.go, cmd/root_integration_test.go, cmd/startup_brand_test.go
Strengthens binary autosave assertions, uses a fixture API catalog for strict-mode testing, and requires matching startup helper nonces.
Live test command and documentation
Makefile, AGENTS.md
Adds and documents the focused live-skills-test target.

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

Sequence Diagram(s)

sequenceDiagram
  participant Makefile
  participant prepareLiveSkillsIntegration
  participant SkillsCLI
  participant UpdateCommand
  Makefile->>prepareLiveSkillsIntegration: enable selected live tests
  prepareLiveSkillsIntegration->>SkillsCLI: redirect home, config, and npm paths
  SkillsCLI-->>UpdateCommand: provide seeded global skills state
  UpdateCommand->>SkillsCLI: synchronize skills state
Loading

Possibly related PRs

Suggested labels: bugfix

Suggested reviewers: maxhuang22, liangshuo-1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: isolating tests from user state.
Description check ✅ Passed The description covers summary, changes, and validation; only the section labels differ from the template.
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
  • Commit unit tests in branch fix/isolate-live-skills-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.

@github-actions github-actions Bot added size/L Large or sensitive change across domains or core paths and removed size/S Low-risk docs, CI, test, or chore only changes labels Jul 14, 2026

@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 `@cmd/update/update_test.go`:
- Around line 1696-1701: Update TestUpdateCommand_SkillsSyncColdStart to create
and defer-cancel a 90-second context, then use it for the skills CLI commands.
Before collecting global skills with “skills ls -g”, seed the isolated
environment by running the same “skills add” command for lark-calendar with
global and noninteractive flags, skipping with descriptive errors if listing or
seeding fails.
🪄 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: 745563ab-abbf-4e2d-be84-6a235eb2a292

📥 Commits

Reviewing files that changed from the base of the PR and between 37d490a and 09679cc.

📒 Files selected for processing (1)
  • cmd/update/update_test.go

Comment thread cmd/update/update_test.go
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@70482b21599dde155f5c2ab35a5007fa0355248c

🧩 Skill update

npx skills add larksuite/cli#fix/isolate-live-skills-tests -y -g

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.38462% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.71%. Comparing base (1c36744) to head (70482b2).
⚠️ Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
internal/registry/registrytest/registrytest.go 65.38% 10 Missing and 8 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1883      +/-   ##
==========================================
+ Coverage   74.66%   74.71%   +0.04%     
==========================================
  Files         877      887      +10     
  Lines       91731    92673     +942     
==========================================
+ Hits        68494    69239     +745     
- Misses      17926    18067     +141     
- Partials     5311     5367      +56     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@luozhixiong01 luozhixiong01 force-pushed the fix/isolate-live-skills-tests branch from ed1060c to 05345c2 Compare July 14, 2026 11:27
@luozhixiong01 luozhixiong01 changed the title test(update): isolate live skills integration tests test: isolate unit tests from user state Jul 14, 2026
luozhixiong01 added a commit that referenced this pull request Jul 15, 2026
Address PR #1883 review blockers and additional findings:

- Redirect XDG_STATE_HOME in live skills tests: the skills CLI writes its
  global .skill-lock.json under $XDG_STATE_HOME, escaping the temp home
  (review P1-1). Also isolate npm_config_cache/prefix/userconfig (both
  cases) which take precedence over HOME-derived npm defaults.
- Seed a tracked registry metadata fixture (calendar/im/task, version
  0.0.1) through a new internal/registry/registrytest package so targeted
  go test passes on a clean checkout with no network, no make fetch_meta,
  and no user cache (review P1-2). The fixture yields to any real
  generated catalog; Seed self-checks both directions and neutralizes
  ambient LARKSUITE_CLI_REMOTE_META/LARKSUITE_CLI_META_TTL overrides.
- Apply the same seeding to cmd/auth so its registry-backed completion
  tests are hermetic instead of reaching for remote metadata (review P1-3).
- Fail hard (t.Fatal) on missing live-test preconditions once
  LARKSUITE_CLI_RUN_LIVE_SKILLS_TESTS=1 is set, so make live-skills-test
  can no longer skip everything and still report success (review P1-4).
- Seed lark-calendar in the cold-start live test so the per-skill
  assertions run on a non-empty list, and share one preflight helper
  between both live tests (review P2-5).
- Pin the binary autosave isolation contract: parse saved_path, assert
  the file lands in the temp cwd with the expected content (review P2-6).
- Guard TestComputeMinimumScopeSet with ensureFreshRegistry and wait for
  background refresh goroutines before removing the registry test root.
- Isolate internal/cmdutil tests from the developer's real ~/.lark-cli.
- Give TestUpdateManual_JSON/Human per-test config dirs so skills-state
  no longer leaks across tests in the shared package dir.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/registry/registry_test.go (1)

103-110: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not discard the deterministic registry fixture before this assertion.

ensureFreshRegistry resets the seeded registry, points it at an empty directory, and disables remote metadata. On a clean checkout this can make ListFromMetaProjects() empty and silently skip the test. Retain the package-level seed or re-seed before Init.

Proposed fix
 func TestComputeMinimumScopeSet(t *testing.T) {
-	ensureFreshRegistry(t)
 	minSet := ComputeMinimumScopeSet("user")

As per coding guidelines, every behavior change must have a test whose assertions directly pin the changed behavior.

🤖 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 `@internal/registry/registry_test.go` around lines 103 - 110, Update
TestComputeMinimumScopeSet so ensureFreshRegistry does not discard the
deterministic package-level registry fixture before the assertion; retain the
seeded registry or re-seed it before initialization. Ensure the test exercises
the seeded metadata path and cannot silently skip due to an empty
ListFromMetaProjects result, with assertions directly covering the preserved
fixture behavior.

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.

Outside diff comments:
In `@internal/registry/registry_test.go`:
- Around line 103-110: Update TestComputeMinimumScopeSet so ensureFreshRegistry
does not discard the deterministic package-level registry fixture before the
assertion; retain the seeded registry or re-seed it before initialization.
Ensure the test exercises the seeded metadata path and cannot silently skip due
to an empty ListFromMetaProjects result, with assertions directly covering the
preserved fixture behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 303d38fd-2b15-46ae-9942-93363b39ee13

📥 Commits

Reviewing files that changed from the base of the PR and between 05345c2 and e0ac9c2.

📒 Files selected for processing (13)
  • cmd/api/api_test.go
  • cmd/auth/testmain_test.go
  • cmd/root_integration_test.go
  • cmd/service/testmain_test.go
  • cmd/startup_brand_test.go
  • cmd/testmain_test.go
  • cmd/update/update_test.go
  • internal/cmdutil/testmain_test.go
  • internal/registry/registry_test.go
  • internal/registry/registrytest/fixture_meta.json
  • internal/registry/registrytest/registrytest.go
  • internal/registry/registrytest/registrytest_test.go
  • internal/registry/testmain_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/registry/testmain_test.go
  • internal/cmdutil/testmain_test.go
  • cmd/auth/testmain_test.go

Address the PR review blockers and follow-up findings in one pass:

- Redirect XDG_STATE_HOME in live skills tests: the skills CLI writes its
  global .skill-lock.json under $XDG_STATE_HOME, escaping the temp home.
  Also isolate npm_config_cache/prefix/userconfig (both cases), which
  take precedence over HOME-derived npm defaults.
- Seed a tracked, hand-trimmed registry metadata fixture (calendar/im/
  task, version 0.0.1, 1.7KB) through a new internal/registry/registrytest
  package so targeted go test passes on a clean checkout with no network,
  no make fetch_meta, and no user cache. The fixture yields to any real
  generated catalog; Seed neutralizes ambient LARKSUITE_CLI_REMOTE_META /
  LARKSUITE_CLI_META_TTL overrides, refuses config dirs outside the
  caller's test root, and self-checks both arbitration directions. Its
  load-bearing content is pinned by a fixture contract test.
- Apply the same seeding to cmd, cmd/service and cmd/auth TestMains so
  registry-backed tests are hermetic instead of reaching for remote
  metadata; guard the startup-brand re-exec helper with an env +
  command-argument nonce handshake so a lone inherited environment
  variable cannot silently disable package isolation.
- Fail hard (t.Fatal) on missing live-test preconditions once
  LARKSUITE_CLI_RUN_LIVE_SKILLS_TESTS=1 is set, so make live-skills-test
  can no longer skip everything and still report success. Share one
  preflight helper between both live tests and seed lark-calendar in the
  cold-start test so its per-skill assertions run on a non-empty list.
- Pin the binary autosave isolation contract: parse saved_path, assert
  the file lands in the temp cwd with the expected content.
- Close remaining developer-state leaks: stub the skills index fetch in
  three update tests that built Updaters directly, isolate
  internal/cmdutil from the real ~/.lark-cli, give
  TestUpdateManual_JSON/Human per-test config dirs, guard
  TestComputeMinimumScopeSet with ensureFreshRegistry, and wait for
  background refresh goroutines before removing the registry test root.
- Decouple the strict-mode bot integration test from registry metadata
  by using the synthetic fixture catalog.
@luozhixiong01 luozhixiong01 force-pushed the fix/isolate-live-skills-tests branch from e0ac9c2 to 075a956 Compare July 15, 2026 09:51

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

🧹 Nitpick comments (1)
cmd/testmain_test.go (1)

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

Use a helper function to ensure cleanup via defer.

In TestMain, os.Exit bypasses deferred functions. While explicit os.RemoveAll calls handle normal exits and setup errors, if m.Run() panics, the temporary directory will leak.

Consider wrapping the setup and execution in a helper function so you can use defer to guarantee cleanup, which also removes the need for repetitive cleanup calls on error paths.

♻️ Proposed refactor
-func TestMain(m *testing.M) {
+func TestMain(m *testing.M) {
+	os.Exit(run(m))
+}
+
+func run(m *testing.M) int {
 	if isStartupBrandHelper() {
 		// Re-exec helper subprocess (startup_brand_test.go): the parent test
 		// already provides an isolated config dir and disables remote metadata,
 		// and the helper must own the first registry Init to prove the startup
 		// order — do not seed or eagerly initialize here.
-		os.Exit(m.Run())
+		return m.Run()
 	}
 	root, err := os.MkdirTemp("", "lark-cli-cmd-test-*")
 	if err != nil {
 		println("cmd test setup: MkdirTemp failed:", err.Error())
-		os.Exit(2)
+		return 2
 	}
+	defer os.RemoveAll(root)
+
 	if err := os.Setenv("LARKSUITE_CLI_CONFIG_DIR", root); err != nil {
 		println("cmd test setup: Setenv failed:", err.Error())
-		os.RemoveAll(root)
-		os.Exit(2)
+		return 2
 	}
 	if err := registrytest.Seed(root); err != nil {
 		println("cmd test setup: registrytest.Seed failed:", err.Error())
-		os.RemoveAll(root)
-		os.Exit(2)
+		return 2
 	}
-	code := m.Run()
-	os.RemoveAll(root)
-	os.Exit(code)
+	return m.Run()
 }
🤖 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 `@cmd/testmain_test.go` around lines 20 - 46, Refactor TestMain by moving
temporary-directory setup, registrytest.Seed, and m.Run into a helper function
that defers os.RemoveAll(root) immediately after creating the directory. Keep
TestMain responsible for startup-helper handling and exiting with the helper’s
result, and remove repetitive cleanup calls from setup-error paths while
preserving their existing exit codes.
🤖 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.

Nitpick comments:
In `@cmd/testmain_test.go`:
- Around line 20-46: Refactor TestMain by moving temporary-directory setup,
registrytest.Seed, and m.Run into a helper function that defers
os.RemoveAll(root) immediately after creating the directory. Keep TestMain
responsible for startup-helper handling and exiting with the helper’s result,
and remove repetitive cleanup calls from setup-error paths while preserving
their existing exit codes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c1b3580a-005a-4e5c-9cd1-35b4ff45be89

📥 Commits

Reviewing files that changed from the base of the PR and between e0ac9c2 and 075a956.

📒 Files selected for processing (13)
  • cmd/api/api_test.go
  • cmd/auth/testmain_test.go
  • cmd/root_integration_test.go
  • cmd/service/testmain_test.go
  • cmd/startup_brand_test.go
  • cmd/testmain_test.go
  • cmd/update/update_test.go
  • internal/cmdutil/testmain_test.go
  • internal/registry/registry_test.go
  • internal/registry/registrytest/fixture_meta.json
  • internal/registry/registrytest/registrytest.go
  • internal/registry/registrytest/registrytest_test.go
  • internal/registry/testmain_test.go
🚧 Files skipped from review as they are similar to previous changes (11)
  • internal/cmdutil/testmain_test.go
  • internal/registry/registrytest/fixture_meta.json
  • internal/registry/registry_test.go
  • cmd/auth/testmain_test.go
  • internal/registry/testmain_test.go
  • cmd/service/testmain_test.go
  • cmd/startup_brand_test.go
  • cmd/root_integration_test.go
  • cmd/api/api_test.go
  • internal/registry/registrytest/registrytest.go
  • cmd/update/update_test.go

Seed's success path (cache writes, eager Init, both self-checks) had no
coverage from the package's own tests — only the rejection branches did —
leaving the patch below the 60% codecov target. Pin it: cache files land
under the config dir, LARKSUITE_CLI_REMOTE_META flips to off, and the
seeded catalog serves calendar/im/task.
codecov counts atomic-mode partials against the patch, so the happy-path
test alone left the diff at 53.8% (target 60%). Exercise the three cache
materialization failure branches with same-named files/directories in
the way — cross-platform, no permission tricks — which also pins that
setup failures surface as errors instead of leaving the registry
silently unseeded. Package statement coverage: 72.1%.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant