Skip to content

E2E: replace login priming with an on-demand lock - #113352

Draft
lucatume wants to merge 4 commits into
trunkfrom
update/e2e-login-lock
Draft

E2E: replace login priming with an on-demand lock#113352
lucatume wants to merge 4 commits into
trunkfrom
update/e2e-login-lock

Conversation

@lucatume

@lucatume lucatume commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Proposed Changes

  • TestAccount.ensureFreshAuthCookies() logs an account in behind a lock file in COOKIES_PATH, so a run logs each account in once rather than once per worker.
  • authenticate() saves the cookies it obtains. It never did, so the ~70 specs that build a TestAccount directly re-logged-in on every test.
  • Removes the prime-logins setup project, AUTHENTICATE_ACCOUNTS, the four TeamCity params setting it, and the priming half of the legacy Jest global setup.

Why are these changes being made?

The priming list was hand-maintained per build type and drifted from what the specs use. An account missing from it got no priming at all and every worker logged it in separately.

Testing Instructions

Against CALYPSO_BASE_URL=$CALYPSO_STAGING_URL, with test/e2e/cookies removed:

cd test/e2e
BRANCH_NAME=trunk DEBUG=true npx playwright test specs/plugins/plugins__browse.spec.ts \
  --project=chrome --project=pixel --project=webkit --workers=4 --reporter=list

Expect one Logging in via Login Page line and one Saving auth cookies, the rest Found fresh cookies, skipping log in, and every test green. Run again with the cookies in place: no login at all.

yarn jest --config packages/calypso-e2e/jest.config.js --rootDir packages/calypso-e2e covers the lock itself: 8 concurrent workers producing one login, release on success and on throw, stale-lock takeover, and the wait ending on freshness rather than on the file existing.

What a reviewer should check: the waiter's exit condition is hasFreshAuthCookies(), not the cookies file existing. A file left by an earlier run can be there and expired, and waiting on existence hands every waiter a dead session.

Pre-merge Checklist

  • Has the general commit checklist been followed? (PCYsg-hS-p2)
  • Have you written new tests for your changes?
  • Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
  • Have you checked for TypeScript, React or other console errors?
  • For UI changes, have you tested the affected components in dark mode?
  • Have you tested accessibility for your changes? Ensure the feature remains usable with various user agents (e.g., browsers), interfaces (e.g., keyboard navigation), and assistive technologies (e.g., screen readers) (PCYsg-S3g-p2).
  • Have you used memoizing on expensive computations? More info in Memoizing with create-selector and Using memoizing selectors and Our Approach to Data
  • Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
    • For UI changes, have we tested the change in various languages (for example, ES, PT, FR, or DE)?
  • For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?

@lucatume lucatume self-assigned this Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Looks like one of the E2E tests has failed.

You can fix them following these steps:

  1. Check out this branch locally:
    gh pr checkout 113352
  2. Start Claude Code in the repo:
    claude
  3. Run the /fix-e2e-tests skill, passing this PR number:
    /fix-e2e-tests 113352
    

Workers share one cookies file per account through COOKIES_PATH, and a CI
build starts with none of them. Every worker misses at once and logs in
concurrently, against a calypso.live container that has just been created.

TestAccount.ensureFreshAuthCookies coordinates through a lock file beside
the cookies: the worker that creates it logs in and writes the cookies,
the rest poll for those cookies and skip the login. A lock older than 45s
belongs to a worker Playwright tore down mid-login, and gets taken over by
rename so that only one of several waiters can claim it. A waiter that has
waited a minute logs in unlocked rather than burn its test timeout.

authenticate() now saves the cookies it obtains, which it never did: the
accounts reached only through it re-logged-in on every test.
The setup project logged in as a hand-maintained per-build-type list of
accounts before the suite, so the specs would find cookies rather than all
log in at once. The list drifted from what the specs use, and an account
missing from it got no priming at all. The login lock covers the same
ground without a list.

Removes the project, the env var behind it and the four TeamCity params
setting it, along with the priming half of the legacy Jest global setup,
which has had no specs to prime since the last one moved to Playwright
Test.
The lock could be lost without its holder noticing: a worker whose login
ran past the stale window had the lock taken from under it and wrote the
cookies anyway, and the takeover raced with the release.

The lock is now a directory holding an ownership marker the holder checks
before it writes anything, with a heartbeat keeping the mtime current so a
slow login isn't mistaken for a dead worker. Every change to that
directory runs under a proper-lockfile guard, so acquire, takeover and
release can't interleave. A failed login gets one retry while the lock is
still held.

The account fixtures no longer log in when they're built; they hand back a
TestAccount and authenticate() does the work, so a spec that only wants
credentials or the REST client pays nothing for them. That left
get-account with nothing to do.
The guard that serializes changes to the lock directory is now built the
same way as the lock itself, out of mkdir and an owner directory whose
mtime a heartbeat keeps current. One less dependency for a few lines that
already existed next to it. Taking over a stale lock now tolerates losing
the mkdir race rather than throwing.

The account fixtures authenticate again on first use, through getAccount.
Handing back an unauthenticated TestAccount pushed the call into every
spec that took a fixture and left the ones that didn't make it silently
logged out.
@lucatume
lucatume force-pushed the update/e2e-login-lock branch from c59c927 to f428704 Compare August 6, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants