Skip to content

Commit

Permalink
Fix PsRunner (#983)
Browse files Browse the repository at this point in the history
* Update psRunner to fix tests

* Add fix for PSModulePath
  • Loading branch information
KonstantinTyukalov authored Oct 31, 2023
1 parent 8890bcd commit 35fb31e
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 58 deletions.
24 changes: 14 additions & 10 deletions powershell/Tests/L0/_suite.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
/// <reference path="../../definitions/mocha.d.ts"/>
/// <reference path="../../definitions/node.d.ts"/>
import psRunner from '../lib/psRunner';
import path from 'path';
import fs from 'fs';
import shell from 'shelljs';

const ps = shell.which('powershell.exe')?.stdout;
if (!ps) {
throw new Error('powershell.exe not found');
}

// Clean PSModulePath to prevent failure due to already loaded modules.
delete process.env['PSModulePath'];

import assert = require('assert');
import psRunner = require('../lib/psRunner');
import path = require('path');
import fs = require('fs');
let shell = require('shelljs');
let ps: string = shell.which('powershell.exe');
describe('VstsTaskSdk Suite', function () {
this.timeout(20000);

before((done: MochaDone): void => {
before((done: Mocha.Done): void => {
done();
});

Expand All @@ -23,7 +27,7 @@ describe('VstsTaskSdk Suite', function () {
let fullPath: string = path.join(__dirname, file);
if (file.match(/\.ps1$/)) {
let description: string = path.basename(file, '.ps1');
it(description, (done: MochaDone) => {
it(description, (done: Mocha.Done) => {
psRunner.run(fullPath, done);
});
}
Expand Down
92 changes: 53 additions & 39 deletions powershell/Tests/lib/psRunner.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,65 @@
/// <reference path="../../definitions/node.d.ts"/>
import { EventEmitter } from 'events';
import { ChildProcess, spawn } from 'child_process';

import events = require('events');
import fs = require('fs');
import path = require('path');
import child = require('child_process');
let shell = require('shelljs');
import shell from 'shelljs';

function debug(message: string): void {
if (process.env['TASK_TEST_TRACE']) {
console.log(message);
}
}

class PSEngineRunner extends events.EventEmitter {
// Thanks to https://stackoverflow.com/a/34637436
class DeferredPromise {
public promise: Promise<void>
public resolve: () => void
public reject: (reason: any) => void

constructor() {
this.promise = new Promise((resolve, reject) => {
this.reject = reject
this.resolve = resolve
})
}
}

class PSEngineRunner extends EventEmitter {
constructor() {
super();
}

private _childProcess: child.ChildProcess;
private _errors: string[];
private _runDeferred: Promise<void>;
private childProcess: ChildProcess;
private errors: string[];
private dp: DeferredPromise;

public stderr: string;
public stdout: string;

public ensureKill(): void {
if (this._childProcess) {
this._childProcess.kill();
if (this.childProcess) {
this.childProcess.kill();
}

this._childProcess = undefined;
}

public run(psPath: string, done) {
public run(psPath: string, done: (err?: any) => void): void {
this.ensureStarted();
this.runPromise(psPath)
.then(() => {
done();
})
.catch((err) => {
done(err);
});
.then(() => done())
.catch((err) => done(err));
}

private ensureStarted(): void {
if (this._childProcess) {
if (this.childProcess) {
return;
}

const powershell = shell.which('powershell.exe')?.stdout;
if (!powershell) {
throw new Error('powershell.exe not found');
}

this.emit('starting');
var powershell = shell.which('powershell.exe').stdout;
this._childProcess = child.spawn(
this.childProcess = spawn(
powershell, // command
[ // args
'-NoLogo',
Expand All @@ -65,51 +75,55 @@ class PSEngineRunner extends events.EventEmitter {
cwd: __dirname,
env: process.env
});
this._childProcess.stdout.on(
this.childProcess.stdout.on(
'data',
(data) => {
// Check for special ouput indicating end of test.
if (('' + data).indexOf('_END_OF_TEST_ce10a77a_') >= 0) {
if (this._errors.length > 0) {
this._runDeferred = Promise.reject(this._errors.join('\n'));
if (this.errors.length > 0) {
this.dp.reject(this.errors.join('\n'));
} else {
this._runDeferred = Promise.resolve();
this.dp.resolve();
}
} else if (data != '\n') {
if (('' + data).match(/##vso\[task.logissue .*type=error/)) {
// The VstsTaskSdk converts error records to error issue commands.
debug('stdout: ' + data);
this._errors.push(data);
this.errors.push(data);
} else {
// Otherwise, normal stdout.
debug('stdout: ' + data);
}
}
});
this._childProcess.stderr.on(
this.childProcess.stderr.on(
'data',
(data) => {
// Stderr indicates an error record was written to PowerShell's error pipeline.
debug('stderr: ' + data);
this._errors.push(data);
this.errors.push(data);
});
}

private runPromise(psPath: string): Promise<void> {
this.emit('running test');
this._errors = [];
this._runDeferred = Promise.resolve();
this._childProcess.stdin.write(psPath + '\n')
return this._runDeferred;

this.errors = [];
this.dp = new DeferredPromise();
this.childProcess.stdin.write(psPath + '\n')

return this.dp.promise;
}
}

let _engineRunner: PSEngineRunner = new PSEngineRunner();
const engineRunner: PSEngineRunner = new PSEngineRunner();

export function run(psPath: string, done): void {
_engineRunner.run(psPath, done);
export function run(psPath: string, done: (err?: any) => void): void {
engineRunner.run(psPath, done);
}

export function ensureStopped(): void {
_engineRunner.ensureKill();
engineRunner.ensureKill();
}

export default { run, ensureStopped };
8 changes: 4 additions & 4 deletions powershell/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ target.build = function () {
fs.writeFileSync(targetPsd1, psd1Contents, 'utf-8');
}

target.test = function () {
util.ensureTool('tsc', '--version', 'Version 1.8.7');
target.test = function() {
util.ensureTool('tsc', '--version', 'Version 4.0.2');
util.ensureTool('mocha', '--version', '5.2.0');
target.build();

util.mkdir('-p', testPath);
util.run(`tsc --outDir "${testPath}" --module commonjs --target es6 --rootDir Tests Tests/lib/psRunner.ts`);
util.run(`tsc --outDir "${testPath}" --module commonjs --target es6 --rootDir Tests Tests/L0/_suite.ts`);
util.run(`tsc --outDir "${testPath}" --module commonjs --target es6 --esModuleInterop --rootDir Tests Tests/lib/psRunner.ts`);
util.run(`tsc --outDir "${testPath}" --module commonjs --target es6 --esModuleInterop --rootDir Tests Tests/L0/_suite.ts`);
util.cp('-r', path.join('Tests', '*'), testPath);
util.run('mocha "' + path.join(testPath, 'L0', '_suite.js') + '"');
}
Expand Down
44 changes: 41 additions & 3 deletions powershell/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions powershell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
"author": "Microsoft",
"license": "MIT",
"devDependencies": {
"@types/mocha": "^5.2.7",
"@types/node": "^10.17.60",
"@types/shelljs": "^0.8.14",
"adm-zip": "^0.5.9",
"deasync": "^0.1.28",
"mocha": "5.2.0",
"nodejs-file-downloader": "^4.11.1",
"shelljs": "^0.8.5",
"typescript": "1.8.7",
"nodejs-file-downloader": "^4.11.1"
"typescript": "^4.0.2"
}
}

0 comments on commit 35fb31e

Please sign in to comment.