Skip to content

Commit

Permalink
Use Sinon for mocking. Fill a test gap for Linux PATH. Add tests with…
Browse files Browse the repository at this point in the history
… task runner. (#7054)
  • Loading branch information
brcrista authored May 7, 2018
1 parent c00e91d commit 5f0da7b
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 206 deletions.
238 changes: 33 additions & 205 deletions Tasks/UsePythonVersion/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,227 +2,55 @@ import * as assert from 'assert';
import { EOL } from 'os';
import * as path from 'path';

import * as mockery from 'mockery';
import * as mockTask from 'vsts-task-lib/mock-task';
import { MockTestRunner } from 'vsts-task-lib/mock-test';

import { Platform } from '../taskutil';
import * as usePythonVersion from '../usepythonversion';

/** Reload the unit under test to use mocks that have been registered. */
function reload(): typeof usePythonVersion {
return require('../usepythonversion');
function didSetVariable(testRunner: MockTestRunner, variableName: string, variableValue: string): boolean {
return testRunner.stdOutContained(`##vso[task.setvariable variable=${variableName};issecret=false;]${variableValue}`);
}

describe('UsePythonVersion L0 Suite', function () {
before(function () {
mockery.enable({
useCleanCache: true,
warnOnUnregistered: false
});
});

after(function () {
mockery.disable();
describe('usepythonversion.ts', function () {
require('./L0_usepythonversion');
});

afterEach(function () {
mockery.deregisterAll();
mockery.resetCache();
})

it('converts Python prerelease versions to the semantic version format', function () {
mockery.registerMock('vsts-task-lib/task', mockTask);
mockery.registerMock('vsts-task-tool-lib/tool', {});
const uut = reload();

const testCases = [
{
versionSpec: '3.x',
expected: '3.x'
},
{
versionSpec: '3.3.6',
expected: '3.3.6'
},
{
versionSpec: '3.7.0b2',
expected: '3.7.0-b2'
},
{
versionSpec: '3.7.0rc',
expected: '3.7.0-rc'
},
{
versionSpec: '14.22.100a1000',
expected: '14.22.100-a1000'
},
{
versionSpec: '3.6.6b2 || >= 3.7.0rc',
expected: '3.6.6-b2 || >= 3.7.0-rc'
},
{
versionSpec: '3.7rc1', // invalid
expected: '3.7rc1'
},
];

for (let tc of testCases) { // Node 5 can't handle destructuring assignment
const actual = uut.pythonVersionToSemantic(tc.versionSpec);
assert.strictEqual(actual, tc.expected);
}
})

it('finds version in cache', async function () {
let buildVariables: { [key: string]: string } = {};
const mockBuildVariables = {
setVariable: (variable: string, value: string) => {
buildVariables[variable] = value;
},
getVariable: (variable: string) => buildVariables[variable]
};
mockery.registerMock('vsts-task-lib/task', Object.assign({}, mockTask, mockBuildVariables));
it('succeeds when version is found', function () {
const testFile = path.join(__dirname, 'L0SucceedsWhenVersionIsFound.js');
const testRunner = new MockTestRunner(testFile);

const toolPath = path.join('/', 'Python', '3.6.4', 'x64');
mockery.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: () => toolPath
});
testRunner.run();

const uut = reload();
const parameters = {
versionSpec: '3.6',
addToPath: false,
architecture: 'x64'
};

assert.strictEqual(buildVariables['pythonLocation'], undefined);

await uut.usePythonVersion(parameters, Platform.Linux);
assert.strictEqual(buildVariables['pythonLocation'], toolPath);
assert(didSetVariable(testRunner, 'pythonLocation', path.join('/', 'Python', '3.6.4', 'x64')));
assert.strictEqual(testRunner.stderr.length, 0, 'should not have written to stderr');
assert(testRunner.succeeded, 'task should have succeeded');
});

it('rejects version not in cache', async function (done: MochaDone) {
mockery.registerMock('vsts-task-lib/task', mockTask);
mockery.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: () => null,
findLocalToolVersions: () => ['2.6.0', '2.7.13']
});
it('fails when version is not found', function () {
const testFile = path.join(__dirname, 'L0FailsWhenVersionIsMissing.js');
const testRunner = new MockTestRunner(testFile);

const uut = reload();
const parameters = {
versionSpec: '3.x',
addToPath: false,
architecture: 'x64'
};
testRunner.run();

try {
await uut.usePythonVersion(parameters, Platform.Linux);
done(new Error('should not have succeeded'));
} catch (e) {
const expectedMessage = [
'loc_mock_VersionNotFound 3.x',
'loc_mock_ListAvailableVersions',
'2.6.0 (x86)',
'2.7.13 (x86)',
'2.6.0 (x64)',
'2.7.13 (x64)'
].join(EOL);
const errorMessage = [
'loc_mock_VersionNotFound 3.x',
'loc_mock_ListAvailableVersions',
'2.6.0 (x86)',
'2.7.13 (x86)',
'2.6.0 (x64)',
'2.7.13 (x64)'
].join(EOL);

assert.strictEqual(e.message, expectedMessage);
done();
}
assert(testRunner.createdErrorIssue(errorMessage));
assert(testRunner.failed, 'task should have failed');
});

it('selects architecture passed as input', async function () {
let buildVariables: { [key: string]: string } = {};
const mockBuildVariables = {
setVariable: (variable: string, value: string) => {
buildVariables[variable] = value;
},
getVariable: (variable: string) => buildVariables[variable]
};
mockery.registerMock('vsts-task-lib/task', Object.assign({}, mockTask, mockBuildVariables));

const x86ToolPath = path.join('/', 'Python', '3.6.4', 'x86');
const x64ToolPath = path.join('/', 'Python', '3.6.4', 'x64');
mockery.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: (toolName: string, versionSpec: string, arch?: string) => {
if (arch === 'x86') {
return x86ToolPath;
} else {
return x64ToolPath;
}
}
});

const uut = reload();
const parameters = {
versionSpec: '3.6',
addToPath: false,
architecture: 'x86'
};

assert.strictEqual(buildVariables['pythonLocation'], undefined);

await uut.usePythonVersion(parameters, Platform.Linux);
assert.strictEqual(buildVariables['pythonLocation'], x86ToolPath);
});

it('sets PATH correctly on Linux', async function () {
mockery.registerMock('vsts-task-lib/task', mockTask);

const toolPath = path.join('/', 'Python', '3.6.4', 'x64');
mockery.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: () => toolPath,
});

let mockPath = '';
mockery.registerMock('./toolutil', {
prependPathSafe: (s: string) => {
mockPath = s + ':' + mockPath;
}
});

const uut = reload();
const parameters = {
versionSpec: '3.6',
addToPath: true,
architecture: 'x64'
};

await uut.usePythonVersion(parameters, Platform.Linux);
assert.strictEqual(`${path.join(toolPath, 'bin')}:${toolPath}:`, mockPath);
});

it('sets PATH correctly on Windows', async function () {
mockery.registerMock('vsts-task-lib/task', mockTask);

const toolPath = path.join('/', 'Python', '3.6.4', 'x64');
mockery.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: () => toolPath
});

let mockPath = '';
mockery.registerMock('./toolutil', {
prependPathSafe: (s: string) => {
mockPath = s + ';' + mockPath;
}
});

process.env['APPDATA'] = '/mock-appdata';

const uut = reload();
const parameters = {
versionSpec: '3.6',
addToPath: true,
architecture: 'x64'
};
it('selects architecture passed as input', function () {
const testFile = path.join(__dirname, 'L0SelectsArchitecture.js');
const testRunner = new MockTestRunner(testFile);

await uut.usePythonVersion(parameters, Platform.Windows);
testRunner.run();

// On Windows, must add the two "Scripts" directories to PATH as well
const expectedScripts = path.join(toolPath, 'Scripts');
const expectedUserScripts = path.join(process.env['APPDATA'], 'Python', 'Python36', 'Scripts');
const expectedPath = `${expectedUserScripts};${expectedScripts};${toolPath};`;
assert.strictEqual(expectedPath, mockPath);
assert(didSetVariable(testRunner, 'pythonLocation', 'x86ToolPath'));
assert.strictEqual(testRunner.stderr.length, 0, 'should not have written to stderr');
assert(testRunner.succeeded, 'task should have succeeded');
});
});
18 changes: 18 additions & 0 deletions Tasks/UsePythonVersion/Tests/L0FailsWhenVersionIsMissing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as path from 'path';

import { TaskMockRunner } from 'vsts-task-lib/mock-run';

const taskPath = path.join(__dirname, '..', 'main.js');
const taskRunner = new TaskMockRunner(taskPath);

taskRunner.setInput('versionSpec', '3.x');
taskRunner.setInput('addToPath', 'false');
taskRunner.setInput('architecture', 'x64');

// Mock vsts-task-tool-lib
taskRunner.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: () => null,
findLocalToolVersions: () => ['2.6.0', '2.7.13']
});

taskRunner.run();
22 changes: 22 additions & 0 deletions Tasks/UsePythonVersion/Tests/L0SelectsArchitecture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as path from 'path';

import * as sinon from 'sinon';

import { TaskMockRunner } from 'vsts-task-lib/mock-run';

const taskPath = path.join(__dirname, '..', 'main.js');
const taskRunner = new TaskMockRunner(taskPath);

taskRunner.setInput('versionSpec', '3.x');
taskRunner.setInput('addToPath', 'false');
taskRunner.setInput('architecture', 'x86');

// Mock vsts-task-tool-lib
const findLocalTool = sinon.stub();
findLocalTool.withArgs(sinon.match.any, sinon.match.any, 'x86').returns('x86ToolPath');
findLocalTool.withArgs(sinon.match.any, sinon.match.any, 'x64').returns('x64ToolPath');
taskRunner.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: findLocalTool
});

taskRunner.run();
18 changes: 18 additions & 0 deletions Tasks/UsePythonVersion/Tests/L0SucceedsWhenVersionIsFound.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as path from 'path';

import { TaskMockRunner } from 'vsts-task-lib/mock-run';

const taskPath = path.join(__dirname, '..', 'main.js');
const taskRunner = new TaskMockRunner(taskPath);

taskRunner.setInput('versionSpec', '3.x');
taskRunner.setInput('addToPath', 'false');
taskRunner.setInput('architecture', 'x64');

// Mock vsts-task-tool-lib
const toolPath = path.join('/', 'Python', '3.6.4', 'x64');
taskRunner.registerMock('vsts-task-tool-lib/tool', {
findLocalTool: () => toolPath
});

taskRunner.run();
Loading

0 comments on commit 5f0da7b

Please sign in to comment.