') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); chore: disable selflink test on apple silicon by lukekarrys · Pull Request #7411 · npm/cli · GitHub
Skip to content

chore: disable selflink test on apple silicon - #7411

Merged
lukekarrys merged 1 commit into
latestfrom
lk/arborist-selflink-test
Apr 24, 2024
Merged

chore: disable selflink test on apple silicon#7411
lukekarrys merged 1 commit into
latestfrom
lk/arborist-selflink-test

Conversation

@lukekarrys

@lukekarryslukekarrys commented Apr 24, 2024

Copy link
Copy Markdown
Contributor

Arborist CI has started failing on macos-latest now that those runners default to arm64 machines (aka Apple Silicon). I am able to reproduce the failures locally on a Macbook Pro M1.

After spending some time debugging the issue I believe it has to do with the timing of Node vs Link creation. I was able to bisect and find #5376 which removed the ability for nodes to possibly take longer to create than their link targets.

Going back to the commit before that PR the flaky test passes locally for me and fails starting with the first commit in that PR.

I'm just running the offending test in a loop and seeing if it fails, so not a perfect metric. But when it fails, I get a failure at least 10% of the time. On the old commit I was able to run it 50x with no failures. Here's what I was running locally to observe failures:

COUNT="0"whiletrue;do
COUNT=$((COUNT+1))echo"Start $COUNT"if! npm test -w workspaces/arborist --ignore-scripts -- test/arborist/load-actual.js --no-coverage -Rtap --grep selflink;thenecho"Failed on run $COUNT"exit 1
fidone

This is definitely an edge case, but one I would like to fix in the future. Disabling this test is to temporarily get CI green while we release and make more substantial changes that are hard to do with CI flaking.

We've had other issues with symlinks and I would feel much better knowing we have defined behavior in this specific case when tracking down future potential symlink bugs.

One fix that worked locally is iterating over node.target.children sequentially instead of in Promise.all] but that is probably only a side effect of the dep ordering in the test. A fix will have to account for any order of links and node taking different amount of time.

@lukekarrys
lukekarrysforce-pushed the lk/arborist-selflink-test branch from 4edf804 to c1152e9CompareApril 24, 2024 16:47
@lukekarryslukekarrys changed the title chore: disable selflink testchore: disable selflink test on apple siliconApr 24, 2024
@wraithgar

Copy link
Copy Markdown
Contributor

Is this really just test flakiness or does this represent a real bug/race condition that we have for folks?

@lukekarrys

Copy link
Copy Markdown
ContributorAuthor

I think there is a real bug here. The only thing I'm unsure of is how much of an edge case this is. The flaky test uses a symlink back to itself, which I consider more of an edge case than if all symlinks could hit this race condition.

@lukekarrys
lukekarrys merged commit dd39de7 into latestApr 24, 2024
@lukekarrys
lukekarrys deleted the lk/arborist-selflink-test branch April 24, 2024 17:32
@github-actionsgithub-actionsBot mentioned this pull request Apr 24, 2024
@liamcmitchell

Copy link
Copy Markdown
Contributor

Looks like this was handled before 2db6c08

@liamcmitchell

liamcmitchell commented Oct 5, 2025

Copy link
Copy Markdown
Contributor

Race loading link (node_modules/@scope/z/node_modules/glob) and target node (node_modules/foo/node_modules/glob). On failure I see the following sequence:

  • node: loadFSNode(), no cached, await PackageJson.normalize(real)
  • link: loadFSNode(), no cached, await PackageJson.normalize(real) (reading same file in parallel)
  • link: await newLink(), target not found, a default target is created with no parent, cache.set(realpath, link.target), await loadFSTree(link.target)
  • node: newNode(), cache.set(path, node), overwriting the link target above which is still loading

So glob children are loaded, but into a duplicate node with no parent.

Ideally solved by caching node promises.

Sign up for freeto 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.

3 participants

@lukekarrys@wraithgar@liamcmitchell