Skip to content

Serialize Mops test dependency installs - #461

Draft
Kamirus wants to merge 1 commit into
masterfrom
cursor/fix-motoko-4-6-tests-e5eb
Draft

Serialize Mops test dependency installs#461
Kamirus wants to merge 1 commit into
masterfrom
cursor/fix-motoko-4-6-tests-e5eb

Conversation

@Kamirus

@Kamirus Kamirus commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Prevents release/update CI from corrupting shared Mops package installs while preparing test fixtures. The Motoko update workflow can now install fixture dependencies deterministically before running the completion and hover test suites.

Before this, fixture installs ran concurrently and could leave zero-byte package files in .mops, causing later language-server tests to fail unpredictably with missing completions or hover data.

Validation: npm install "motoko@^4.6.0" --min-release-age=0 && npm run compile && npm test passes with 24 suites / 276 tests.

Slack Thread

Open in Web Open in Cursor 

@Kamirus
Kamirus marked this pull request as ready for review May 21, 2026 11:16
@Kamirus
Kamirus requested a review from a team as a code owner May 21, 2026 11:16
@Kamirus

Kamirus commented May 21, 2026

Copy link
Copy Markdown
Collaborator Author

We need to update mops to be safe calling install in parallel

@Kamirus
Kamirus marked this pull request as draft May 21, 2026 11:50
Kamirus added a commit to caffeinelabs/mops that referenced this pull request May 22, 2026
## Why

Two `mops` processes installing into the same project (editor watcher,
[vscode-motoko's fixture
installer](caffeinelabs/vscode-motoko#461), CI
matrix sharing a global cache) race on cache writes and leave zero-byte
/ truncated files in `.mops/`. Symptom downstream: missing completions,
hover, type-check errors. v2.13.2's concurrent-invocations fix covered
`check`/`build`/`check-stable` scratch dirs, not the install cache path.

Two race windows:

- **Global cache** (`install-mops-dep.ts`): `Promise.all(mkdir +
writeFile)` writes directly into `cacheDir` while `isDepCached =
fs.existsSync(cacheDir)` — peer sees "cached" mid-write and copies a
half-populated tree.
- **Local `.mops/<pkg>`** (`syncLocalCache`): two concurrent installs
both miss `existsSync(dest)` and interleave writes via `ncp`.

GitHub installs were strictly worse — `mkdirSync(cacheDir)` ran *before*
the download, so peers saw an empty dir as cached. The shared
`.mops/_tmp/` zip dir was also clobbered by concurrent github installs.

## What

Cache writes stage into a sibling `.staging-*` dir (`mkdtemp`, same
filesystem) and **atomically `rename` onto the canonical path**.
Race-loser catches `ENOTEMPTY` / `EEXIST` / `EPERM` (only when `dest`
exists, to avoid masking real Windows AV / permission errors), drops its
staging, and observes a complete cache. Applies to mops registry
installs, github installs, local `.mops/` sync, and the github zip
download dir. Stale staging is swept on the next install with a 1h mtime
cutoff.

## Test plan

- [x] New test: 5 parallel `mops install` runs against an isolated
`XDG_CACHE_HOME` produce no zero-byte files and no `.staging-*`
leftovers (cold-cache path actually exercised).
- [x] Existing `parallel builds of the same canister both succeed` still
passes.
- [x] Full CLI test suite: 104 passed.
- [x] `npm run check` + `npm run lint` clean.

Refs LANG-1310, caffeinelabs/vscode-motoko#461.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
@caffeine-ci-bot

Copy link
Copy Markdown
Contributor

This draft pull request has had no activity for 60 days and has been marked as stale. It will not be closed automatically. Please close it if you can.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants