Files
ccs/tests
Sergey Galuza 00a4dceb94 fix(shared-manager): publish adopted settings by replacement
Adoption moved the canonical settings.json aside with rename() and left
the path empty until publication, roughly 100 ms later. Claude Code or a
second `ccs` starting inside that window found no file and seeded an
empty placeholder; publication then failed with EEXIST because link() is
no-replace, and the rollback published a backup and unlinked the claim,
destroying the only remaining copy of the user's settings. Recovering
meant digging through sidecar files by hand.

Publish by replacement instead: write a temp file next to the canonical
inode and rename() it over the target, so the path always holds a regular
file and no placeholder can be seeded. A compare-and-swap guard on
(ino, mtime, size) runs immediately before the rename and refuses to
publish when the canonical inode changed since it was read, so a writer
that got there first is still never clobbered. The pre-image backup is
published before the replacement, keeping the old content recoverable if
publication is interrupted.

Drops the canonical claim entirely along with restoreCanonicalClaim, and
folds the two identical sidecar publishers into one helper.
recoverOrphanedCanonicalClaim stays, since claims written by older
versions may still be on disk.

New tests cover both writers seen in the incident: Claude Code seeding
`{}` with a trailing newline, and a second `ccs` seeding the 2-byte
variant from shared-dir-linker. Four tests that pinned the claim-based
design were rewritten, among them `preserves a canonical write that
lands during no-replace publication`, whose intent is now enforced by
the CAS guard instead of by an EEXIST from a no-replace link.

Built [OnSteroids](https://onsteroids.ai)
2026-08-23 08:32:26 +02:00
..

CCS Test Suite

Root TypeScript and JavaScript tests run with Bun's test runner. Native shell, PowerShell, Docker, and standalone probes cover contracts that need a real platform or process boundary.

Ownership

Area Path Use for
Unit unit/ Focused module and command behavior
Integration integration/ Cross-module, process, proxy, auth, and web-server behavior
End to end e2e/ Packaged CLI workflows
npm package npm/ Installation, exports, and package behavior
Native native/ Unix and Windows shell behavior
Docker docker/ Compose and stable network/service contracts
Documentation docs/ Repository documentation invariants
Shared support shared/ Fixtures and helpers reused by suites
Mocks mocks/ Bounded test doubles and fixtures

Some source domains also keep focused tests in src/**/__tests__/. Follow the nearest established pattern and avoid moving tests solely for taxonomy.

Commands

Commands are defined in ../package.json. Bucket membership and execution live in ../scripts/run-test-bucket.js.

bun run test:fast      # Fast Bun test bucket
bun run test:slow      # Slow Bun test bucket
bun run test:all       # All root non-e2e Bun test buckets
bun run test:unit      # tests/unit
bun run test:npm       # tests/npm
bun run test:native    # Native Unix edge-case script
bun run test:e2e       # tests/e2e with fail-fast and extended timeout
bun run test           # Build, then test:all

For the normal contributor gate:

bun run format
bun run lint:fix
bun run validate

For the closest local equivalent to PR CI:

bun run validate:ci-parity

Dashboard tests use Vitest and are documented in ../ui/README.md.

Test Isolation

  • Set CCS_HOME to a temporary directory.
  • Never read or modify a contributor's real ~/.ccs/ or ~/.claude/.
  • Use getCcsDir() from ../src/utils/config-manager.ts for CCS paths.
  • Keep fixtures deterministic and free of credentials or private account data.
  • Use real behavior at the boundary under test; do not weaken assertions to hide regressions.

Adding Coverage

  • Add a focused unit test for isolated logic.
  • Add integration coverage when behavior crosses modules, processes, HTTP, or persistence boundaries.
  • Add e2e coverage when command routing or packaged CLI behavior is the contract.
  • Add native or Docker coverage only when platform/runtime behavior cannot be represented faithfully in Bun tests.
  • Run the smallest relevant command first, then broaden to the contributor or CI-parity gate when shared contracts changed.