Skip to content

Commit

Permalink
cherry pick 6fae1bd (#8416)
Browse files Browse the repository at this point in the history
  • Loading branch information
brcrista authored Sep 26, 2018
1 parent b8a7d30 commit 61c4345
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@
"loc.messages.InstallFailed": "Failed to install packages. %s",
"loc.messages.ReactivateExistingEnvironment": "Found existing environment %s and the task's \"Clean environment\" parameter is not set. Reactivating ...",
"loc.messages.ParameterRequired": "The `%s` parameter is required",
"loc.messages.PlatformNotRecognized": "Platform not recognized"
"loc.messages.PlatformNotRecognized": "Platform not recognized",
"loc.messages.PrependPath": "Prepending PATH environment variable with directory: %s"
}
16 changes: 14 additions & 2 deletions Tasks/CondaEnvironmentV1/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as path from 'path';

import { MockTestRunner } from 'vsts-task-lib/mock-test';

import { getPlatform, Platform } from '../taskutil';

describe('CondaEnvironment L0 Suite', function () {
describe('conda.ts', function () {
require('./L0_conda');
Expand All @@ -19,7 +21,12 @@ describe('CondaEnvironment L0 Suite', function () {

testRunner.run();

assert(testRunner.ran(`conda create --quiet --prefix ${path.join('/', 'miniconda', 'envs', 'test')} --mkdir --yes`));
if (getPlatform() === Platform.Windows) {
assert(testRunner.ran('conda create --quiet --prefix \\miniconda\\envs\\test --mkdir --yes'));
} else {
assert(testRunner.ran('sudo conda create --quiet --prefix /miniconda/envs/test --mkdir --yes'));
}

assert.strictEqual(testRunner.stderr.length, 0, 'should not have written to stderr');
assert(testRunner.succeeded, 'task should have succeeded');
});
Expand All @@ -30,7 +37,12 @@ describe('CondaEnvironment L0 Suite', function () {

testRunner.run();

assert(testRunner.ran('conda install python=3 --quiet --yes --json'));
if (getPlatform() === Platform.Windows) {
assert(testRunner.ran('conda install python=3 --quiet --yes --json'));
} else {
assert(testRunner.ran('sudo conda install python=3 --quiet --yes --json'));
}

assert.strictEqual(testRunner.stderr.length, 0, 'should not have written to stderr');
assert(testRunner.succeeded, 'task should have succeeded');
});
Expand Down
14 changes: 12 additions & 2 deletions Tasks/CondaEnvironmentV1/Tests/L0BaseEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@ taskRunner.setAnswers({
'conda': '/miniconda/bin/conda'
},
exec: {
'sudo conda install python=3 --quiet --yes --json': {
code: 0
},
'conda install python=3 --quiet --yes --json': {
'code': 0
}
code: 0
},
'/miniconda/bin/conda info --base': {
code: 0,
stdout: '/base/environment'
},
},
checkPath: {
'/miniconda/bin/conda': true
}
});

Expand Down
6 changes: 3 additions & 3 deletions Tasks/CondaEnvironmentV1/Tests/L0CreateEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ taskRunner.setAnswers({
'conda': '/miniconda/bin/conda'
},
exec: {
'conda create --quiet --prefix /miniconda/envs/test --mkdir --yes': {
'code': 0
'sudo conda create --quiet --prefix /miniconda/envs/test --mkdir --yes': {
code: 0
},
'conda create --quiet --prefix \\miniconda\\envs\\test --mkdir --yes': {
'code': 0
code: 0
},
}
});
Expand Down
62 changes: 52 additions & 10 deletions Tasks/CondaEnvironmentV1/Tests/L0_conda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ it('creates and activates environment', async function () {
await uut.condaEnvironment(parameters, Platform.Linux);
assert(findConda.calledOnceWithExactly(Platform.Linux));
assert(prependCondaToPath.calledOnceWithExactly('path-to-conda', Platform.Linux));
assert(createEnvironment.calledOnceWithExactly(path.join('path-to-conda', 'envs', 'env'), undefined, undefined));
assert(createEnvironment.calledOnceWithExactly(path.join('path-to-conda', 'envs', 'env'), Platform.Linux, undefined, undefined));
assert(activateEnvironment.calledOnceWithExactly(path.join('path-to-conda', 'envs'), 'env', Platform.Linux));
});

Expand Down Expand Up @@ -124,7 +124,7 @@ it('updates Conda if the user requests it', async function () {
assert(updateConda.calledOnceWithExactly('path-to-conda', Platform.Linux));
});

it('fails if `conda` is not found', async function (done: MochaDone) {
it('fails if `conda` is not found', async function () {
mockery.registerMock('fs', {
existsSync: () => false
});
Expand All @@ -147,15 +147,57 @@ it('fails if `conda` is not found', async function (done: MochaDone) {
updateConda: false
};

// Can't use `assert.throws` with an async function
// Node 10: use `assert.rejects`
let error: any | undefined;
try {
await uut.condaEnvironment(parameters, Platform.Windows);
done(new Error('should not have succeeded'));
} catch (e) {
assert.strictEqual(e.message, 'loc_mock_CondaNotFound');
assert(findConda.calledOnceWithExactly(Platform.Windows));
assert(prependCondaToPath.notCalled);
assert(createEnvironment.notCalled);
assert(activateEnvironment.notCalled);
done();
error = e;
}
});

assert(error instanceof Error);
assert.strictEqual(error.message, 'loc_mock_CondaNotFound');

assert(findConda.calledOnceWithExactly(Platform.Windows));
assert(prependCondaToPath.notCalled);
assert(createEnvironment.notCalled);
assert(activateEnvironment.notCalled);
});

it('fails if installing packages to the base environment fails', async function () {
mockery.registerMock('vsts-task-lib/task', mockTask);

const findConda = sinon.stub().returns('path-to-conda');
const prependCondaToPath = sinon.spy();
const installPackagesGlobally = sinon.stub().rejects(new Error('installPackagesGlobally'));

mockery.registerMock('./conda_internal', {
findConda: findConda,
prependCondaToPath: prependCondaToPath,
installPackagesGlobally: installPackagesGlobally
});

const uut = reload('../conda');
const parameters = {
createCustomEnvironment: false,
packageSpecs: 'pytest',
updateConda: false
};

// Can't use `assert.throws` with an async function
// Node 10: use `assert.rejects`
let error: any | undefined;
try {
await uut.condaEnvironment(parameters, Platform.Linux);
} catch (e) {
error = e;
}

assert(error instanceof Error);
assert.strictEqual(error.message, 'installPackagesGlobally');

assert(findConda.calledOnceWithExactly(Platform.Linux));
assert(prependCondaToPath.calledOnceWithExactly('path-to-conda', Platform.Linux));
assert(installPackagesGlobally.calledOnceWithExactly('pytest', Platform.Linux, undefined));
});
133 changes: 88 additions & 45 deletions Tasks/CondaEnvironmentV1/Tests/L0_conda_internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ it('finds the Conda installation with the CONDA variable', async function () {
getVariable: getVariable
}));

mockery.registerMock('vsts-task-tool-lib/tool', {});

{ // executable exists and is a file
existsSync.returns(true);
statSync.returns({
Expand Down Expand Up @@ -114,55 +112,71 @@ it('finds the Conda installation with PATH', async function () {
getVariable: getVariable
}));

mockery.registerMock('vsts-task-tool-lib/tool', {});

const uut = reload('../conda_internal');

assert.strictEqual(uut.findConda(Platform.Linux), 'path-to-conda');
assert.strictEqual(uut.findConda(Platform.MacOS), 'path-to-conda');
assert.strictEqual(uut.findConda(Platform.Windows), 'path-to-conda');
});

it('creates Conda environment', async function (done: MochaDone) {
it('creates Conda environment', async function () {
mockery.registerMock('vsts-task-lib/task', mockTask);
mockery.registerMock('vsts-task-lib/toolrunner', mockToolRunner);
mockery.registerMock('vsts-task-tool-lib/tool', {});
const uut = reload('../conda_internal');

{ // success
mockToolRunner.setAnswers({
exec: {
'conda create --quiet --prefix envsDir/env --mkdir --yes': {
code: 0
},
// workaround for running tests cross-platform
'conda create --quiet --prefix envsDir\\env --mkdir --yes': {
code: 0
}
for (const platform of [Platform.Windows, Platform.Linux, Platform.MacOS])
{
{ // success
if (platform === Platform.Windows) {
mockToolRunner.setAnswers({
exec: {
[`conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
code: 0
}
}
});
} else {
mockToolRunner.setAnswers({
exec: {
[`sudo conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
code: 0
}
}
});
}
});

await uut.createEnvironment(path.join('envsDir', 'env'));
}
{ // failure
mockToolRunner.setAnswers({
exec: {
'conda create --quiet --prefix envsDir/env --mkdir --yes': {
code: 1
},
// workaround for running tests cross-platform
'conda create --quiet --prefix envsDir\\env --mkdir --yes': {
code: 1
}
await uut.createEnvironment(path.join('envsDir', 'env'), platform);
}
{ // failure
if (platform === Platform.Windows) {
mockToolRunner.setAnswers({
exec: {
[`conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
code: 1
}
}
});
} else {
mockToolRunner.setAnswers({
exec: {
[`sudo conda create --quiet --prefix ${path.join('envsDir', 'env')} --mkdir --yes`]: {
code: 1
}
}
});
}
});

try {
await uut.createEnvironment(path.join('envsDir', 'env'));
done(new Error('should not have succeeded'));
} catch (e) {
assert.strictEqual(e.message, `loc_mock_CreateFailed ${path.join('envsDir', 'env')} Error: conda failed with return code: 1`);
done();
// Can't use `assert.throws` with an async function
// Node 10: use `assert.rejects`
let error: any | undefined;
try {
await uut.createEnvironment(path.join('envsDir', 'env'), platform);
} catch (e) {
error = e;
}

assert(error instanceof Error);
assert.strictEqual(error.message, `loc_mock_CreateFailed ${path.join('envsDir', 'env')} Error: ${platform === Platform.Windows ? 'conda' : 'sudo'} failed with return code: 1`);
}
}
});
Expand All @@ -173,37 +187,66 @@ it('activates Conda environment', async function () {
setVariable: setVariable
}));

const prependPath = sinon.spy();
mockery.registerMock('vsts-task-tool-lib/tool', {
prependPath: prependPath
const prependPathSafe = sinon.spy();
mockery.registerMock('./toolutil', {
prependPathSafe: prependPathSafe
});

const uut = reload('../conda_internal');

{ // Linux
uut.activateEnvironment('envs', 'env', Platform.Linux);
assert(prependPath.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
assert(prependPathSafe.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
assert(setVariable.calledTwice);
assert(setVariable.calledWithExactly('CONDA_DEFAULT_ENV', 'env'));
assert(setVariable.calledWithExactly('CONDA_PREFIX', path.join('envs', 'env')));
}
{ // macOS
setVariable.resetHistory();
prependPath.resetHistory();
prependPathSafe.resetHistory();
uut.activateEnvironment('envs', 'env', Platform.MacOS);
assert(prependPath.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
assert(prependPathSafe.calledOnceWithExactly(path.join('envs', 'env', 'bin')));
assert(setVariable.calledTwice);
assert(setVariable.calledWithExactly('CONDA_DEFAULT_ENV', 'env'));
assert(setVariable.calledWithExactly('CONDA_PREFIX', path.join('envs', 'env')));
}
{ // Windows
setVariable.resetHistory();
prependPath.resetHistory();
prependPathSafe.resetHistory();
uut.activateEnvironment('envs', 'env', Platform.Windows);
assert(prependPath.calledWithExactly(path.join('envs', 'env')));
assert(prependPath.calledWithExactly(path.join('envs', 'env', 'Scripts')));
assert(prependPathSafe.calledWithExactly(path.join('envs', 'env')));
assert(prependPathSafe.calledWithExactly(path.join('envs', 'env', 'Scripts')));
assert(setVariable.calledTwice);
assert(setVariable.calledWithExactly('CONDA_DEFAULT_ENV', 'env'));
assert(setVariable.calledWithExactly('CONDA_PREFIX', path.join('envs', 'env')));
}
});

it('adds base environment to path successfully', function () {
mockTask.setAnswers({
which: {
'conda': '/miniconda/bin/conda'
},
exec: {
'/miniconda/bin/conda info --base': {
code: 0,
stdout: '/base/environment'
}
},
checkPath: {
'/miniconda/bin/conda': true
}
});

mockery.registerMock('vsts-task-lib/task', mockTask);

const prependPathSafe = sinon.spy();
mockery.registerMock('./toolutil', {
prependPathSafe: prependPathSafe
});

const uut = reload('../conda_internal');
uut.addBaseEnvironmentToPath(Platform.Linux);

assert(prependPathSafe.calledOnceWithExactly(path.join('/base/environment', 'bin')));
});
Loading

0 comments on commit 61c4345

Please sign in to comment.