Skip to content

Commit

Permalink
Unzip extract async bug (#7724)
Browse files Browse the repository at this point in the history
* Added test case to verify failing unzip.

* Chaining async execution of unzipExtract to run.

The Java Tool Installer Task fails when the jdk is provided as a zip
file.

The issue is caused by the extractFiles method not awaiting the
async result of the unzipExtract method. Instead the extractFiles method
returns before the unzip powershell command has been executed causing the task to fail.

Addressed the issue by chaining the async execution of the unzipExtract
method through to the async run method of the task.
  • Loading branch information
osmanrafiqss authored and keljos committed Jul 20, 2018
1 parent 6ae79b6 commit b9dc36e
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 6 deletions.
8 changes: 4 additions & 4 deletions Tasks/JavaToolInstallerV0/FileExtractor/JavaFilesExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class JavaFilesExtractor {
tr.exec();
}

private extractFiles(file: string, fileEnding: string) {
private async extractFiles(file: string, fileEnding: string) {
const stats = taskLib.stats(file);
if (!stats) {
throw new Error(taskLib.loc('ExtractNonExistFile', file));
Expand Down Expand Up @@ -104,7 +104,7 @@ export class JavaFilesExtractor {
console.log(taskLib.loc('RemoveTempDir', tempFolder));
taskLib.rmRF(tempFolder);
} else if ('.zip' === fileEnding) {
this.unzipExtract(file, this.destinationFolder);
await this.unzipExtract(file, this.destinationFolder);
} else { // use sevenZip
this.sevenZipExtract(file, this.destinationFolder);
}
Expand Down Expand Up @@ -139,7 +139,7 @@ export class JavaFilesExtractor {
}
}

public unzipJavaDownload(repoRoot: string, fileEnding: string, extractLocation: string): string {
public async unzipJavaDownload(repoRoot: string, fileEnding: string, extractLocation: string): Promise<string> {
this.destinationFolder = extractLocation;
let initialDirectoriesList: string[];
let finalDirectoriesList: string[];
Expand All @@ -156,7 +156,7 @@ export class JavaFilesExtractor {
const jdkFile = path.normalize(repoRoot);
const stats = taskLib.stats(jdkFile);
if (stats.isFile()) {
this.extractFiles(jdkFile, fileEnding);
await this.extractFiles(jdkFile, fileEnding)
finalDirectoriesList = taskLib.find(this.destinationFolder).filter(x => taskLib.stats(x).isDirectory());
taskLib.setResult(taskLib.TaskResult.Succeeded, taskLib.loc('SucceedMsg'));
jdkDirectory = finalDirectoriesList.filter(dir => initialDirectoriesList.indexOf(dir) < 0)[0];
Expand Down
10 changes: 10 additions & 0 deletions Tasks/JavaToolInstallerV0/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,14 @@ describe('JavaToolInstaller L0 Suite', function () {
assert(testRunner.failed, 'task should have failed');
done();
});

it('should run succesfully when extracting zip file', (done) => {
const testPath: string = path.join(__dirname, 'L0UnzipTest.js');
const testRunner: ttm.MockTestRunner = new ttm.MockTestRunner(testPath);

testRunner.run();

assert(testRunner.succeeded, 'task should have succedded');
done();
});
});
98 changes: 98 additions & 0 deletions Tasks/JavaToolInstallerV0/Tests/L0UnzipTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import mockanswer = require('vsts-task-lib/mock-answer');
import mockrun = require('vsts-task-lib/mock-run');
import path = require('path');

var Q = require('q');

const taskPath = path.join(__dirname, '..', 'javatoolinstaller.js');
const srcPath = 'source/foo.zip';
const destDir = '/destDir';

// task parameters
const tr: mockrun.TaskMockRunner = new mockrun.TaskMockRunner(taskPath);
tr.setInput("versionSpec", "8.1");
tr.setInput("jdkSourceOption", "Local Directory");
tr.setInput("jdkFile", srcPath);
tr.setInput("jdkDestinationDirectory", destDir);
tr.setInput("cleanDestinationDirectory", "false");
tr.setInput("jdkArchitectureOption", "x64");

// set windir
process.env.windir = 'windir';

// provide answers for task mock
const a: mockanswer.TaskLibAnswers = <mockanswer.TaskLibAnswers>{
exist: {[destDir]: true},
which: {'windir\\system32\\chcp.com': 'windir\\system32\\chcp.com'},
checkPath: {'windir\\system32\\chcp.com': true },
find: {[destDir]: [destDir]},
rmRF: { },
osType: {'osType': 'Win32'},
stats: {[destDir]: {'isDirectory':'true'}, 'source\\foo.zip': {'isFile':'true'}, '/destDir/foo': {'isDirectory':'true'}},
};
tr.setAnswers(a);

// toolrunner that mimicks modification of the directory structure following a powershell unzip command
var MockToolRunner = function (tool) {
var _tool;
var _line;
var _args;

this.init = function(tool) {
this._tool = tool;
};

this.arg = function (args) {
this._args = args;
return this;
};

this.line = function (val) {
this._line = val;
return this;
};

this.exec = function (options) {
var _this = this;
var defer = Q.defer();
console.log('exec: ' + _this._tool + ' line: ' + _this._line + ' args: ' + _this._args);

// Simulate som asynchronous event through timer
setTimeout(function() {
if (_this._tool == 'powershell') {
// update to pretend an unzip actually occurred
a.find = {[destDir]: [destDir, '/destDir/foo']};
console.log('directories updated: ' + a.find[destDir]);
}
defer.resolve(0);
}, 100);
return defer.promise;
};

this.execSync = function(options) {
console.log('execSync: ' + this._tool + ' line: ' + this._line + ' args: ' + this._args);
return this;
};

this.init(tool);
};

tr.registerMockExport('tool', function(tool){
return new MockToolRunner(tool);
});

// tool mock
tr.registerMock('vsts-task-tool-lib/tool', {
debug: function(message) {
console.log('##debug : ' + message);
},

findLocalToolVersions: function(fileName) {
return null;
},
evaluateVersions: function(fileName) {
return null;
}
});

tr.run();
6 changes: 4 additions & 2 deletions Tasks/JavaToolInstallerV0/javatoolinstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ async function getJava(versionSpec: string) {
await sleepFor(250); //Wait for the file to be released before extracting it.

const extractSource = buildFilePath(extractLocation, compressedFileExtension, fileNameAndPath);
jdkDirectory = new JavaFilesExtractor().unzipJavaDownload(extractSource, compressedFileExtension, extractLocation);
const javaFilesExtractor = new JavaFilesExtractor();
jdkDirectory = await javaFilesExtractor.unzipJavaDownload(extractSource, compressedFileExtension, extractLocation);
} else { //JDK is in a local directory. Extract to specified target directory.
console.log(taskLib.loc('RetrievingJdkFromLocalPath'));
compressedFileExtension = getFileEnding(taskLib.getInput('jdkFile', true));
jdkDirectory = new JavaFilesExtractor().unzipJavaDownload(taskLib.getInput('jdkFile', true), compressedFileExtension, extractLocation);
const javaFilesExtractor = new JavaFilesExtractor();
jdkDirectory = await javaFilesExtractor.unzipJavaDownload(taskLib.getInput('jdkFile', true), compressedFileExtension, extractLocation);
}

let extendedJavaHome = 'JAVA_HOME_' + versionSpec + '_' + taskLib.getInput('jdkArchitectureOption', true);
Expand Down

0 comments on commit b9dc36e

Please sign in to comment.