Sanity tests perf improvements (#296248)

This commit is contained in:
Dmitriy Vasyura
2026-02-22 08:55:53 -08:00
committed by GitHub
parent 939e20b2a0
commit ee401a1256
16 changed files with 238 additions and 254 deletions

View File

@@ -32,6 +32,7 @@ interface ITargetMetadata {
*/
export class TestContext {
private static readonly authenticodeInclude = /^.+\.(exe|dll|sys|cab|cat|msi|jar|ocx|ps1|psm1|psd1|ps1xml|pssc1)$/i;
private static readonly versionInfoInclude = /^.+\.(exe|dll|node|msi)$/i;
private readonly tempDirs = new Set<string>();
private readonly wslTempDirs = new Set<string>();
@@ -61,15 +62,12 @@ export class TestContext {
/**
* Returns the OS temp directory with expanded long names on Windows.
*/
public readonly osTempDir = (function () {
public readonly osTempDir = (() => {
let tempDir = fs.realpathSync(os.tmpdir());
// On Windows, expand short 8.3 file names to long names
if (os.platform() === 'win32') {
const result = spawnSync('powershell', ['-Command', `(Get-Item "${tempDir}").FullName`], { encoding: 'utf-8' });
if (result.status === 0 && result.stdout) {
tempDir = result.stdout.trim();
}
tempDir = fs.realpathSync.native(tempDir);
}
return tempDir;
@@ -298,39 +296,12 @@ export class TestContext {
const { url, sha256hash } = await this.fetchMetadata(target);
const filePath = path.join(this.createTempDir(), path.basename(url));
const maxRetries = 5;
let lastError: Error | undefined;
this.log(`Downloading ${url} to ${filePath}`);
this.runNoErrors('curl', '-fSL', '--retry', '5', '--retry-delay', '2', '--retry-all-errors', '-o', filePath, url);
this.log(`Downloaded ${url} to ${filePath}`);
for (let attempt = 0; attempt < maxRetries; attempt++) {
if (attempt > 0) {
const delay = Math.pow(2, attempt - 1) * 1000;
this.log(`Retrying download (attempt ${attempt + 1}/${maxRetries}) after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
try {
this.log(`Downloading ${url} to ${filePath}`);
const { body } = await this.fetchNoErrors(url);
const stream = fs.createWriteStream(filePath);
await new Promise<void>((resolve, reject) => {
body.on('error', reject);
stream.on('error', reject);
stream.on('finish', resolve);
body.pipe(stream);
});
this.log(`Downloaded ${url} to ${filePath}`);
this.validateSha256Hash(filePath, sha256hash);
return filePath;
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
this.log(`Download attempt ${attempt + 1} failed: ${lastError.message}`);
}
}
this.error(`Failed to download ${url} after ${maxRetries} attempts: ${lastError?.message}`);
this.validateSha256Hash(filePath, sha256hash);
return filePath;
}
/**
@@ -360,15 +331,50 @@ export class TestContext {
}
this.log(`Validating Authenticode signature for ${filePath}`);
this.validateAuthenticodeSignaturesForFiles([filePath]);
}
const result = this.run('powershell', '-Command', `Get-AuthenticodeSignature "${filePath}" | Select-Object -ExpandProperty Status`);
if (result.error !== undefined) {
this.error(`Failed to run Get-AuthenticodeSignature: ${result.error.message}`);
/**
* Collects all files matching the Authenticode include pattern from the specified directory recursively.
*/
private collectAuthenticodeFiles(dir: string, files: string[]): void {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const filePath = path.join(dir, entry.name);
if (entry.isDirectory()) {
this.collectAuthenticodeFiles(filePath, files);
} else if (TestContext.authenticodeInclude.test(entry.name)) {
files.push(filePath);
}
}
}
/**
* Validates Authenticode signatures for the specified list of files in a single PowerShell call.
*/
private validateAuthenticodeSignaturesForFiles(files: string[]): void {
if (files.length === 0) {
return;
}
const status = result.stdout.trim();
if (status !== 'Valid') {
this.error(`Authenticode signature is not valid for ${filePath}: ${status}`);
const fileList = files.map(file => `"${file}"`).join(',');
const command = `@(${fileList}) | ForEach-Object { $sig = Get-AuthenticodeSignature $_; "$($sig.Path)|$($sig.Status)" }`;
const result = this.runNoErrors('powershell', '-NoProfile', '-Command', command);
const invalid: string[] = [];
for (const line of result.stdout.trim().split('\n')) {
const [, filePath, status] = /^(.+)\|(\w+)$/.exec(line.trim()) ?? [];
if (filePath) {
if (status === 'Valid') {
this.log(`Authenticode signature is valid for ${filePath}`);
} else {
invalid.push(`${filePath}: ${status}`);
}
}
}
if (invalid.length > 0) {
this.error(`Authenticode signatures are not valid for:\n${invalid.join('\n')}`);
}
}
@@ -382,17 +388,86 @@ export class TestContext {
return;
}
const files = fs.readdirSync(dir, { withFileTypes: true });
for (const file of files) {
const filePath = path.join(dir, file.name);
if (file.isDirectory()) {
this.validateAllAuthenticodeSignatures(filePath);
} else if (TestContext.authenticodeInclude.test(file.name)) {
this.validateAuthenticodeSignature(filePath);
const files: string[] = [];
this.collectAuthenticodeFiles(dir, files);
this.log(`Found ${files.length} file(s) to validate Authenticode signatures`);
this.validateAuthenticodeSignaturesForFiles(files);
}
/**
* Collects all files matching the VersionInfo include pattern from the specified directory recursively.
*/
private collectVersionInfoFiles(dir: string, files: string[]): void {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const filePath = path.join(dir, entry.name);
if (entry.isDirectory()) {
this.collectVersionInfoFiles(filePath, files);
} else if (TestContext.versionInfoInclude.test(entry.name)) {
files.push(filePath);
}
}
}
/**
* Validates that a Windows binary has a non-empty ProductName in VersionInfo.
* @param filePath The path to the file to validate.
*/
public validateVersionInfo(filePath: string) {
if (!this.options.checkSigning || !this.capabilities.has('windows')) {
this.log(`Skipping VersionInfo validation for ${filePath} (signing checks disabled)`);
return;
}
this.log(`Validating VersionInfo for ${filePath}`);
this.validateVersionInfoForFiles([filePath]);
}
/**
* Validates VersionInfo ProductName for the specified list of files in a single PowerShell call.
*/
private validateVersionInfoForFiles(files: string[]): void {
if (files.length === 0) {
return;
}
const fileList = files.map(file => `"${file}"`).join(',');
const command = `@(${fileList}) | ForEach-Object { $vi = (Get-Item $_).VersionInfo; "$($_.ToString())|$($vi.ProductName)" }`;
const result = this.runNoErrors('powershell', '-NoProfile', '-Command', command);
const invalid: string[] = [];
for (const line of result.stdout.trim().split('\n')) {
const [, filePath, productName] = /^(.+)\|(.*)$/.exec(line.trim()) ?? [];
if (filePath) {
if (productName && productName.trim().length > 0) {
this.log(`VersionInfo ProductName is set for ${filePath}: ${productName.trim()}`);
} else {
invalid.push(filePath);
}
}
}
if (invalid.length > 0) {
this.error(`VersionInfo ProductName is missing or empty for:\n${invalid.join('\n')}`);
}
}
/**
* Validates that all .exe, .dll, .node and .msi binaries in the specified directory have a non-empty ProductName in VersionInfo.
* @param dir The directory to scan for binary files.
*/
public validateAllVersionInfo(dir: string) {
if (!this.options.checkSigning || !this.capabilities.has('windows')) {
this.log(`Skipping VersionInfo validation for ${dir} (signing checks disabled)`);
return;
}
const files: string[] = [];
this.collectVersionInfoFiles(dir, files);
this.log(`Found ${files.length} file(s) to validate VersionInfo`);
this.validateVersionInfoForFiles(files);
}
/**
* Validates the codesign signature of a macOS binary or app bundle.
* @param filePath The path to the file or app bundle to validate.