Browse Source

build: fix linux tests (#42496)

* build: use runuser for electron spec runner

* chown

* run tests in priv

* fixed

* build: setup testing on arm for GHA

* no build-tools for test

* start xvfb for the right user

* no more gn-build-type

* debug env

* ue xvfb-run

* use 8 core for node tests

* build: do test sharding on linux

* fix: disable hung node test

* build: index splits are hard

* build: use --init to reap children

* allow write junit

* use custom xvfb wrapper

* pipefail

* dont kill xvfb, its already dead

---------

Co-authored-by: John Kleinschmidt <[email protected]>
Samuel Attard 10 months ago
parent
commit
c2c3673e8a

+ 5 - 2
.github/workflows/build.yml

@@ -114,6 +114,7 @@ jobs:
       build-runs-on: aks-linux-large
       test-runs-on: aks-linux-medium
       build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      test-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root --privileged --init"}'
       target-platform: linux
       target-arch: x64
       is-release: false
@@ -127,8 +128,9 @@ jobs:
     needs: checkout-linux
     with:
       build-runs-on: aks-linux-large
-      test-runs-on: aks-linux-medium
+      test-runs-on: aks-linux-arm-medium
       build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ inputs.build-image-sha }}","options":"--user root --privileged --init"}'
       target-platform: linux
       target-arch: arm
       is-release: false
@@ -142,8 +144,9 @@ jobs:
     needs: checkout-linux
     with:
       build-runs-on: aks-linux-large
-      test-runs-on: aks-linux-medium
+      test-runs-on: aks-linux-arm-medium
       build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ inputs.build-image-sha }}","options":"--user root --privileged --init"}'
       target-platform: linux
       target-arch: arm64
       is-release: false

+ 7 - 3
.github/workflows/pipeline-electron-build-and-test-and-nan.yml

@@ -24,6 +24,11 @@ on:
         description: 'JSON container information for aks runs-on'
         required: false
         default: '{"image":null}'
+      test-container:
+        type: string
+        description: 'JSON container information for testing'
+        required: false
+        default: '{"image":null}'
       is-release:
         description: 'Whether this build job is a release job'
         required: true
@@ -69,8 +74,7 @@ jobs:
       target-arch: ${{ inputs.target-arch }}
       target-platform: ${{ inputs.target-platform }}
       test-runs-on: ${{ inputs.test-runs-on }}
-      test-container: ${{ inputs.build-container }}
-      gn-build-type: ${{ inputs.gn-build-type }}
+      test-container: ${{ inputs.test-container }}
     secrets: inherit
   nn-test:
     uses: ./.github/workflows/pipeline-segment-node-nan-test.yml
@@ -79,6 +83,6 @@ jobs:
       target-arch: ${{ inputs.target-arch }}
       target-platform: ${{ inputs.target-platform }}
       test-runs-on: ${{ inputs.test-runs-on }}
-      test-container: ${{ inputs.build-container }}
+      test-container: ${{ inputs.test-container }}
       gn-build-type: ${{ inputs.gn-build-type }}
     secrets: inherit

+ 6 - 3
.github/workflows/pipeline-electron-build-and-test.yml

@@ -24,6 +24,11 @@ on:
         description: 'JSON container information for aks runs-on'
         required: false
         default: '{"image":null}'
+      test-container:
+        type: string
+        description: 'JSON container information for testing'
+        required: false
+        default: '{"image":null}'
       is-release:
         description: 'Whether this build job is a release job'
         required: true
@@ -64,12 +69,10 @@ jobs:
     secrets: inherit
   test:
     uses: ./.github/workflows/pipeline-segment-electron-test.yml
-    if: ${{ inputs.target-platform == 'macos' || inputs.target-arch == 'x64' }}
     needs: build
     with:
       target-arch: ${{ inputs.target-arch }}
       target-platform: ${{ inputs.target-platform }}
       test-runs-on: ${{ inputs.test-runs-on }}
-      test-container: ${{ inputs.build-container }}
-      gn-build-type: ${{ inputs.gn-build-type }}
+      test-container: ${{ inputs.test-container }}
     secrets: inherit

+ 1 - 1
.github/workflows/pipeline-segment-electron-build.yml

@@ -137,7 +137,7 @@ jobs:
         fetch-depth: 0
     - name: Load Build Tools
       run: |
-        export BUILD_TOOLS_SHA=5e75f554ba5b919b4ed67caa2ba8042d8e3be947
+        export BUILD_TOOLS_SHA=97f6508e27d08c1e41b61b2cdc1250d998b9ff8c
         npm i -g @electron/build-tools
         e auto-update disable
         e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk

+ 14 - 15
.github/workflows/pipeline-segment-electron-test.yml

@@ -20,11 +20,6 @@ on:
         description: 'JSON container information for aks runs-on'
         required: false
         default: '{"image":null}'
-      gn-build-type:
-        description: 'The gn build type - testing or release'
-        required: true
-        type: string
-        default: testing
 
 concurrency:
   group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
@@ -42,16 +37,11 @@ jobs:
       fail-fast: false
       matrix:
         build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || fromJSON('["linux"]') }}
+        shard: ${{ inputs.target-platform == 'macos' && fromJSON('[1]') || fromJSON('[1, 2, 3]') }}
     env:
       BUILD_TYPE: ${{ matrix.build-type }}
       TARGET_ARCH: ${{ inputs.target-arch }}
     steps:
-    - name: Load Build Tools
-      run: |
-        export BUILD_TOOLS_SHA=ef894bc3cfa99d84a3b731252da0f83f500e4032
-        npm i -g @electron/build-tools
-        e auto-update disable
-        e init --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }}
     - name: Checkout Electron
       uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
       with:
@@ -103,9 +93,6 @@ jobs:
     #     sudo security authorizationdb write com.apple.trust-settings.admin allow
     #     cd src/electron
     #     ./script/codesign/generate-identity.sh
-    - name: Setup for headless testing
-      if: ${{ inputs.target-platform == 'linux' }}
-      run: sh -e /etc/init.d/xvfb start
     - name: Run Electron Tests
       env:
         MOCHA_REPORTER: mocha-multi-reporters
@@ -113,9 +100,21 @@ jobs:
         MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
         ELECTRON_DISABLE_SECURITY_WARNINGS: 1
         ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
+        DISPLAY: ':99.0'
       run: |
         cd src/electron
-        node script/yarn test --runners=main --trace-uncaught --enable-logging
+        # Get which tests are on this shard
+        tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ inputs.target-platform == 'macos' && 1 || 3 }})
+
+        # Run tests
+        if [ "`uname`" = "Darwin" ]; then
+          node script/yarn test --runners=main --trace-uncaught --enable-logging
+        else
+          chown :builduser .. && chmod g+w ..
+          chown -R :builduser . && chmod -R g+w .
+          chmod 4755 ../out/Default/chrome-sandbox
+          runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
+        fi
     - name: Wait for active SSH sessions
       if: always() && !cancelled()
       run: |

+ 3 - 3
.github/workflows/pipeline-segment-node-nan-test.yml

@@ -37,7 +37,7 @@ env:
 jobs:
   node-tests:
     name: Run Node.js Tests
-    runs-on: aks-linux-medium
+    runs-on: aks-linux-medium-plus
     timeout-minutes: 20
     env: 
       TARGET_ARCH: ${{ inputs.target-arch }}
@@ -46,7 +46,7 @@ jobs:
     steps:
     - name: Load Build Tools
       run: |
-        export BUILD_TOOLS_SHA=ef894bc3cfa99d84a3b731252da0f83f500e4032
+        export BUILD_TOOLS_SHA=97f6508e27d08c1e41b61b2cdc1250d998b9ff8c
         npm i -g @electron/build-tools
         e auto-update disable
         e init --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }}
@@ -111,7 +111,7 @@ jobs:
     steps:
     - name: Load Build Tools
       run: |
-        export BUILD_TOOLS_SHA=ef894bc3cfa99d84a3b731252da0f83f500e4032
+        export BUILD_TOOLS_SHA=97f6508e27d08c1e41b61b2cdc1250d998b9ff8c
         npm i -g @electron/build-tools
         e auto-update disable
         e init --root=$(pwd) --out=Default ${{ inputs.gn-build-type }}

+ 7 - 0
script/actions/run-tests.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+set -euo pipefail
+
+export DISPLAY=:99
+Xvfb :99 -screen 0 1024x768x16 -ac &
+XVFB_PID=$!
+node "$@"

+ 1 - 0
script/node-disabled-tests.json

@@ -5,6 +5,7 @@
   "parallel/test-child-process-fork-exec-path",
   "parallel/test-code-cache",
   "parallel/test-cluster-primary-error",
+  "parallel/test-cluster-primary-kill",
   "parallel/test-crypto-aes-wrap",
   "parallel/test-crypto-authenticated-stream",
   "parallel/test-crypto-des3-wrap",

+ 32 - 0
script/split-tests.js

@@ -0,0 +1,32 @@
+const fs = require('node:fs');
+const glob = require('glob');
+
+const currentShard = parseInt(process.argv[2], 10);
+const shardCount = parseInt(process.argv[3], 10);
+
+const specFiles = glob.sync('spec/*-spec.ts');
+
+const buckets = [];
+
+for (let i = 0; i < shardCount; i++) {
+  buckets.push([]);
+}
+
+const testsInSpecFile = Object.create(null);
+for (const specFile of specFiles) {
+  const testContent = fs.readFileSync(specFile, 'utf8');
+  testsInSpecFile[specFile] = testContent.split('it(').length;
+}
+
+specFiles.sort((a, b) => {
+  return testsInSpecFile[b] - testsInSpecFile[a];
+});
+
+let shard = 0;
+for (const specFile of specFiles) {
+  buckets[shard].push(specFile);
+  shard++;
+  if (shard === shardCount) shard = 0;
+}
+
+console.log(buckets[currentShard - 1].join(' '));