Skip to content

Commit f37648e

Browse files
joyeecheungrichardlau
authored andcommitted
test: skip SEA tests when SEA generation fails
In the SEA tests, if any of these steps fail: 1. Copy the executable 2. Inject the SEA blob 3. Signing the SEA We skip the test because the error likely comes from the system or postject and is not something the Node.js core can fix. We only leave an exception for a basic test that test injecting empty files as SEA to ensure the workflow is working (but we still skip if copying fails or signing fails on Windows). PR-URL: #51887 Refs: #49630 Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent 9b164c6 commit f37648e

10 files changed

+98
-62
lines changed

test/common/README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -1048,11 +1048,13 @@ Application functionality.
10481048
Skip the rest of the tests if single executable applications are not supported
10491049
in the current configuration.
10501050

1051-
### `injectAndCodeSign(targetExecutable, resource)`
1051+
### `generateSEA(targetExecutable, sourceExecutable, seaBlob, verifyWorkflow)`
10521052

1053-
Uses Postect to inject the contents of the file at the path `resource` into
1054-
the target executable file at the path `targetExecutable` and ultimately code
1055-
sign the final binary.
1053+
Copy `sourceExecutable` to `targetExecutable`, use postject to inject `seaBlob`
1054+
into `targetExecutable` and sign it if necessary.
1055+
1056+
If `verifyWorkflow` is false (default) and any of the steps fails,
1057+
it skips the tests. Otherwise, an error is thrown.
10561058

10571059
## tick Module
10581060

test/common/sea.js

+59-30
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
const common = require('../common');
44
const fixtures = require('../common/fixtures');
55
const tmpdir = require('../common/tmpdir');
6+
const { inspect } = require('util');
67

7-
const { readFileSync } = require('fs');
8+
const { readFileSync, copyFileSync } = require('fs');
89
const {
910
spawnSyncAndExitWithoutError,
1011
} = require('../common/child_process');
@@ -54,47 +55,75 @@ function skipIfSingleExecutableIsNotSupported() {
5455
}
5556
}
5657

57-
function injectAndCodeSign(targetExecutable, resource) {
58+
function generateSEA(targetExecutable, sourceExecutable, seaBlob, verifyWorkflow = false) {
59+
try {
60+
copyFileSync(sourceExecutable, targetExecutable);
61+
} catch (e) {
62+
const message = `Cannot copy ${sourceExecutable} to ${targetExecutable}: ${inspect(e)}`;
63+
if (verifyWorkflow) {
64+
throw new Error(message);
65+
}
66+
common.skip(message);
67+
}
68+
console.log(`Copied ${sourceExecutable} to ${targetExecutable}`);
69+
5870
const postjectFile = fixtures.path('postject-copy', 'node_modules', 'postject', 'dist', 'cli.js');
59-
spawnSyncAndExitWithoutError(process.execPath, [
60-
postjectFile,
61-
targetExecutable,
62-
'NODE_SEA_BLOB',
63-
resource,
64-
'--sentinel-fuse', 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2',
65-
...process.platform === 'darwin' ? [ '--macho-segment-name', 'NODE_SEA' ] : [],
66-
], {});
71+
try {
72+
spawnSyncAndExitWithoutError(process.execPath, [
73+
postjectFile,
74+
targetExecutable,
75+
'NODE_SEA_BLOB',
76+
seaBlob,
77+
'--sentinel-fuse', 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2',
78+
...process.platform === 'darwin' ? [ '--macho-segment-name', 'NODE_SEA' ] : [],
79+
]);
80+
} catch (e) {
81+
const message = `Cannot inject ${seaBlob} into ${targetExecutable}: ${inspect(e)}`;
82+
if (verifyWorkflow) {
83+
throw new Error(message);
84+
}
85+
common.skip(message);
86+
}
87+
console.log(`Injected ${seaBlob} into ${targetExecutable}`);
6788

6889
if (process.platform === 'darwin') {
69-
spawnSyncAndExitWithoutError('codesign', [ '--sign', '-', targetExecutable ], {});
70-
spawnSyncAndExitWithoutError('codesign', [ '--verify', targetExecutable ], {});
90+
try {
91+
spawnSyncAndExitWithoutError('codesign', [ '--sign', '-', targetExecutable ], {});
92+
spawnSyncAndExitWithoutError('codesign', [ '--verify', targetExecutable ], {});
93+
} catch (e) {
94+
const message = `Cannot sign ${targetExecutable}: ${inspect(e)}`;
95+
if (verifyWorkflow) {
96+
throw new Error(message);
97+
}
98+
common.skip(message);
99+
}
100+
console.log(`Signed ${targetExecutable}`);
71101
} else if (process.platform === 'win32') {
72-
let signtoolFound = false;
73102
try {
74103
spawnSyncAndExitWithoutError('where', [ 'signtool' ], {});
75-
signtoolFound = true;
76-
} catch (err) {
77-
console.log(err.message);
78-
}
79-
if (signtoolFound) {
80-
let certificatesFound = false;
81-
let stderr;
82-
try {
83-
({ stderr } = spawnSyncAndExitWithoutError('signtool', [ 'sign', '/fd', 'SHA256', targetExecutable ], {}));
84-
certificatesFound = true;
85-
} catch (err) {
86-
if (!/SignTool Error: No certificates were found that met all the given criteria/.test(stderr)) {
87-
throw err;
88-
}
104+
} catch (e) {
105+
const message = `Cannot find signtool: ${inspect(e)}`;
106+
if (verifyWorkflow) {
107+
throw new Error(message);
89108
}
90-
if (certificatesFound) {
91-
spawnSyncAndExitWithoutError('signtool', 'verify', '/pa', 'SHA256', targetExecutable, {});
109+
common.skip(message);
110+
}
111+
let stderr;
112+
try {
113+
({ stderr } = spawnSyncAndExitWithoutError('signtool', [ 'sign', '/fd', 'SHA256', targetExecutable ], {}));
114+
spawnSyncAndExitWithoutError('signtool', 'verify', '/pa', 'SHA256', targetExecutable, {});
115+
} catch (e) {
116+
const message = `Cannot sign ${targetExecutable}: ${inspect(e)}\n${stderr}`;
117+
if (verifyWorkflow) {
118+
throw new Error(message);
92119
}
120+
common.skip(message);
93121
}
122+
console.log(`Signed ${targetExecutable}`);
94123
}
95124
}
96125

97126
module.exports = {
98127
skipIfSingleExecutableIsNotSupported,
99-
injectAndCodeSign,
128+
generateSEA,
100129
};

test/sequential/test-single-executable-application-assets-raw.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const common = require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -56,8 +56,7 @@ const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'se
5656

5757
assert(existsSync(seaPrepBlob));
5858

59-
copyFileSync(process.execPath, outputFile);
60-
injectAndCodeSign(outputFile, seaPrepBlob);
59+
generateSEA(outputFile, process.execPath, seaPrepBlob);
6160

6261
spawnSyncAndExitWithoutError(
6362
outputFile,

test/sequential/test-single-executable-application-assets.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const common = require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -109,8 +109,7 @@ const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'se
109109

110110
assert(existsSync(seaPrepBlob));
111111

112-
copyFileSync(process.execPath, outputFile);
113-
injectAndCodeSign(outputFile, seaPrepBlob);
112+
generateSEA(outputFile, process.execPath, seaPrepBlob);
114113

115114
spawnSyncAndExitWithoutError(
116115
outputFile,

test/sequential/test-single-executable-application-disable-experimental-sea-warning.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -51,8 +51,7 @@ spawnSyncAndExitWithoutError(
5151

5252
assert(existsSync(seaPrepBlob));
5353

54-
copyFileSync(process.execPath, outputFile);
55-
injectAndCodeSign(outputFile, seaPrepBlob);
54+
generateSEA(outputFile, process.execPath, seaPrepBlob);
5655

5756
spawnSyncAndExitWithoutError(
5857
outputFile,

test/sequential/test-single-executable-application-empty.js

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use strict';
22

3-
require('../common');
3+
const common = require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -13,7 +13,7 @@ skipIfSingleExecutableIsNotSupported();
1313
// script.
1414

1515
const tmpdir = require('../common/tmpdir');
16-
const { copyFileSync, writeFileSync, existsSync } = require('fs');
16+
const { writeFileSync, existsSync } = require('fs');
1717
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
1818
const assert = require('assert');
1919

@@ -38,8 +38,20 @@ spawnSyncAndExitWithoutError(
3838

3939
assert(existsSync(seaPrepBlob));
4040

41-
copyFileSync(process.execPath, outputFile);
42-
injectAndCodeSign(outputFile, seaPrepBlob);
41+
// Verify the workflow.
42+
try {
43+
generateSEA(outputFile, process.execPath, seaPrepBlob, true);
44+
} catch (e) {
45+
if (/Cannot copy/.test(e.message)) {
46+
common.skip(e.message);
47+
} else if (common.isWindows) {
48+
if (/Cannot sign/.test(e.message) || /Cannot find signtool/.test(e.message)) {
49+
common.skip(e.message);
50+
}
51+
}
52+
53+
throw e;
54+
}
4355

4456
spawnSyncAndExitWithoutError(
4557
outputFile,

test/sequential/test-single-executable-application-snapshot-and-code-cache.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -12,7 +12,7 @@ skipIfSingleExecutableIsNotSupported();
1212
// This tests "useCodeCache" is ignored when "useSnapshot" is true.
1313

1414
const tmpdir = require('../common/tmpdir');
15-
const { copyFileSync, writeFileSync, existsSync } = require('fs');
15+
const { writeFileSync, existsSync } = require('fs');
1616
const {
1717
spawnSyncAndExitWithoutError
1818
} = require('../common/child_process');
@@ -62,8 +62,7 @@ const outputFile = join(tmpdir.path, process.platform === 'win32' ? 'sea.exe' :
6262

6363
assert(existsSync(seaPrepBlob));
6464

65-
copyFileSync(process.execPath, outputFile);
66-
injectAndCodeSign(outputFile, seaPrepBlob);
65+
generateSEA(outputFile, process.execPath, seaPrepBlob);
6766

6867
spawnSyncAndExitWithoutError(
6968
outputFile,

test/sequential/test-single-executable-application-snapshot.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -12,7 +12,7 @@ skipIfSingleExecutableIsNotSupported();
1212
// This tests the snapshot support in single executable applications.
1313

1414
const tmpdir = require('../common/tmpdir');
15-
const { copyFileSync, writeFileSync, existsSync } = require('fs');
15+
const { writeFileSync, existsSync } = require('fs');
1616
const {
1717
spawnSyncAndExit,
1818
spawnSyncAndExitWithoutError
@@ -85,8 +85,7 @@ const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'se
8585

8686
assert(existsSync(seaPrepBlob));
8787

88-
copyFileSync(process.execPath, outputFile);
89-
injectAndCodeSign(outputFile, seaPrepBlob);
88+
generateSEA(outputFile, process.execPath, seaPrepBlob);
9089

9190
spawnSyncAndExitWithoutError(
9291
outputFile,

test/sequential/test-single-executable-application-use-code-cache.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -56,8 +56,7 @@ spawnSyncAndExitWithoutError(
5656

5757
assert(existsSync(seaPrepBlob));
5858

59-
copyFileSync(process.execPath, outputFile);
60-
injectAndCodeSign(outputFile, seaPrepBlob);
59+
generateSEA(outputFile, process.execPath, seaPrepBlob);
6160

6261
spawnSyncAndExitWithoutError(
6362
outputFile,

test/sequential/test-single-executable-application.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require('../common');
44

55
const {
6-
injectAndCodeSign,
6+
generateSEA,
77
skipIfSingleExecutableIsNotSupported,
88
} = require('../common/sea');
99

@@ -50,8 +50,7 @@ spawnSyncAndExitWithoutError(
5050

5151
assert(existsSync(seaPrepBlob));
5252

53-
copyFileSync(process.execPath, outputFile);
54-
injectAndCodeSign(outputFile, seaPrepBlob);
53+
generateSEA(outputFile, process.execPath, seaPrepBlob);
5554

5655
spawnSyncAndExitWithoutError(
5756
outputFile,

0 commit comments

Comments
 (0)