Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Set environment variables for go test runs #498

Merged
merged 9 commits into from
Sep 29, 2016
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,11 @@
"type": "string",
"default": "",
"description": "The Go build tags to use for all commands that support a `-tags '...'` argument"
},
"go.testEnvVars": {
"type": "object",
"default": {},
"description": "Environment variables that will passed to the process that runs the Go tests"
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/goMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ export function activate(ctx: vscode.ExtensionContext): void {

ctx.subscriptions.push(vscode.commands.registerCommand('go.test.cursor', () => {
let goConfig = vscode.workspace.getConfiguration('go');
testAtCursor(goConfig['testTimeout']);
testAtCursor(goConfig);
}));

ctx.subscriptions.push(vscode.commands.registerCommand('go.test.package', () => {
let goConfig = vscode.workspace.getConfiguration('go');
testCurrentPackage(goConfig['testTimeout']);
testCurrentPackage(goConfig);
}));

ctx.subscriptions.push(vscode.commands.registerCommand('go.test.file', () => {
let goConfig = vscode.workspace.getConfiguration('go');
testCurrentFile(goConfig['testTimeout']);
testCurrentFile(goConfig);
}));

ctx.subscriptions.push(vscode.commands.registerCommand('go.test.previous', () => {
Expand Down
47 changes: 25 additions & 22 deletions src/goTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ interface TestConfig {
*/
dir: string;
/**
* The timeout for tests (in ParseDuration format.)
* Configuration for the Go extension
*/
timeout: string;
goConfig: vscode.WorkspaceConfiguration;
/**
* Specific function names to test.
*/
Expand All @@ -39,13 +39,13 @@ let lastTestConfig: TestConfig;
/**
* Executes the unit test at the primary cursor using `go test`. Output
* is sent to the 'Go' channel.
*
* @param timeout a ParseDuration formatted timeout string for the tests.
*
* @param goConfig Configuration for the Go extension.
*
* TODO: go test returns filenames with no path information for failures,
* so output doesn't produce navigable line references.
*/
export function testAtCursor(timeout: string) {
export function testAtCursor(goConfig: vscode.WorkspaceConfiguration) {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
Expand All @@ -66,7 +66,7 @@ export function testAtCursor(timeout: string) {
return;
}
return goTest({
timeout: timeout,
goConfig: goConfig,
dir: path.dirname(editor.document.fileName),
functions: [testFunction.name]
});
Expand All @@ -78,16 +78,16 @@ export function testAtCursor(timeout: string) {
/**
* Runs all tests in the package of the source of the active editor.
*
* @param timeout a ParseDuration formatted timeout string for the tests.
* @param goConfig Configuration for the Go extension.
*/
export function testCurrentPackage(timeout: string) {
export function testCurrentPackage(goConfig: vscode.WorkspaceConfiguration) {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
return;
}
goTest({
timeout: timeout,
goConfig: goConfig,
dir: path.dirname(editor.document.fileName)
}).then(null, err => {
console.error(err);
Expand All @@ -97,22 +97,23 @@ export function testCurrentPackage(timeout: string) {
/**
* Runs all tests in the source of the active editor.
*
* @param timeout a ParseDuration formatted timeout string for the tests.
* @param goConfig Configuration for the Go extension.
*/
export function testCurrentFile(timeout: string) {
export function testCurrentFile(goConfig: vscode.WorkspaceConfiguration): Thenable<boolean> {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
return;
}
getTestFunctions(editor.document).then(testFunctions => {
return getTestFunctions(editor.document).then(testFunctions => {
return goTest({
timeout: timeout,
goConfig: goConfig,
dir: path.dirname(editor.document.fileName),
functions: testFunctions.map(func => { return func.name; })
});
}).then(null, err => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly minor - but this change will mean that any exceptions thrown during execution of goTest are not handled and reported to console.error. A weirdness of .then on promises. Possibly just leave the additional .then call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put the console.error(err) to back where it was and returned promise from there

console.error(err);
return Promise.resolve(false);
});
}

Expand All @@ -133,23 +134,25 @@ export function testPrevious() {
/**
* Runs go test and presents the output in the 'Go' channel.
*
* @param config the test execution configuration.
* @param goConfig Configuration for the Go extension.
*/
function goTest(config: TestConfig): Thenable<boolean> {
function goTest(testconfig: TestConfig): Thenable<boolean> {
return new Promise<boolean>((resolve, reject) => {
// Remember this config as the last executed test.
lastTestConfig = config;
lastTestConfig = testconfig;
outputChannel.clear();
outputChannel.show(2);
let buildFlags: string[] = vscode.workspace.getConfiguration('go')['buildFlags'];
let buildTags: string = vscode.workspace.getConfiguration('go')['buildTags'];
let args = ['test', '-v', '-timeout', config.timeout, '-tags', buildTags, ...buildFlags];

if (config.functions) {
let buildFlags: string[] = testconfig.goConfig['buildFlags'];
let buildTags: string = testconfig.goConfig['buildTags'];
let args = ['test', '-v', '-timeout', testconfig.goConfig['testTimeout'], '-tags', buildTags, ...buildFlags];
let testEnvVars = Object.assign({}, process.env, testconfig.goConfig['testEnvVars']);

if (testconfig.functions) {
args.push('-run');
args.push(util.format('^%s$', config.functions.join('|')));
args.push(util.format('^%s$', testconfig.functions.join('|')));
}
let proc = cp.spawn(getGoRuntimePath(), args, { env: process.env, cwd: config.dir });
let proc = cp.spawn(getGoRuntimePath(), args, { env: testEnvVars, cwd: testconfig.dir });
proc.stdout.on('data', chunk => outputChannel.append(chunk.toString()));
proc.stderr.on('data', chunk => outputChannel.append(chunk.toString()));
proc.on('close', code => {
Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/sample_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"fmt"
"os"
"testing"
)

func hello() {
fmt.Println("Hello")
}

// TestMe
func TestMe(t *testing.T) {
if os.Getenv("dummyEnvVar") != "dummyEnvValue" {
t.Errorf("Oops! Value for the variable is %q", os.Getenv("dummyEnvVar"))
}
}
25 changes: 22 additions & 3 deletions test/go.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { GoHoverProvider } from '../src/goExtraInfo';
import { GoCompletionItemProvider } from '../src/goSuggest';
import { GoSignatureHelpProvider } from '../src/goSignature';
import { check } from '../src/goCheck';
import { testCurrentFile } from '../src/goTest';

suite('Go Extension Tests', () => {
let gopath = process.env['GOPATH'];
Expand All @@ -23,7 +24,8 @@ suite('Go Extension Tests', () => {
fs.removeSync(repoPath);
fs.mkdirsSync(fixturePath);
fs.copySync(path.join(fixtureSourcePath, 'test.go'), path.join(fixturePath, 'test.go'));
fs.copySync(path.join(fixtureSourcePath, 'errors.go'), path.join(fixturePath, 'errors.go'));
fs.copySync(path.join(fixtureSourcePath, 'errorsTest', 'errors.go'), path.join(fixturePath, 'errorsTest', 'errors.go'));
fs.copySync(path.join(fixtureSourcePath, 'sample_test.go'), path.join(fixturePath, 'sample_test.go'));
});

suiteTeardown(() => {
Expand Down Expand Up @@ -117,7 +119,7 @@ encountered.
// { line: 7, severity: 'warning', msg: 'no formatting directive in Printf call' },
{ line: 11, severity: 'error', msg: 'undefined: prin' },
];
check(path.join(fixturePath, 'errors.go'), config).then(diagnostics => {
check(path.join(fixturePath, 'errorsTest', 'errors.go'), config).then(diagnostics => {
let sortedDiagnostics = diagnostics.sort((a, b) => a.line - b.line);
for (let i in expected) {
assert.equal(sortedDiagnostics[i].line, expected[i].line);
Expand Down Expand Up @@ -145,7 +147,7 @@ encountered.
{ line: 11, severity: 'warning', msg: 'unused global variable undeclared name: prin (varcheck)' },
{ line: 11, severity: 'warning', msg: 'unused struct field undeclared name: prin (structcheck)' },
];
check(path.join(fixturePath, 'errors.go'), config).then(diagnostics => {
check(path.join(fixturePath, 'errorsTest', 'errors.go'), config).then(diagnostics => {
let sortedDiagnostics = diagnostics.sort((a, b) => {
if ( a.msg < b.msg )
return -1;
Expand All @@ -161,4 +163,21 @@ encountered.
assert.equal(sortedDiagnostics.length, expected.length, `too many errors ${JSON.stringify(sortedDiagnostics)}`);
}).then(() => done(), done);
});

test('Test Env Variables are passed to Tests', (done) => {
let config = Object.create(vscode.workspace.getConfiguration('go'), {
'testEnvVars': { value: { 'dummyEnvVar': 'dummyEnvValue'} }
});

let uri = vscode.Uri.file(path.join(fixturePath, 'sample_test.go'));
vscode.workspace.openTextDocument(uri).then(document => {
return vscode.window.showTextDocument(document).then(editor => {
return testCurrentFile(config).then((result: boolean) => {
assert.equal(result, true);
return Promise.resolve();
});
});
}).then(() => done(), done);
});

});