Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Sinon for mocking. Fill a test gap for Linux PATH. Add tests with task runner. #7054

Merged
merged 9 commits into from
May 7, 2018
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