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

Support parallel rspec tests #122

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
Copy link
Author

Choose a reason for hiding this comment

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

Happy to remove this one, added as I was testing in codespaces but haven't tweaked it to have everything needed, just a basic starting point

// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-20"

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",

// Configure tool-specific properties.
// "customizations": {},

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- main
pull_request: {}
workflow_dispatch:
Copy link
Author

Choose a reason for hiding this comment

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

Let's you manually start it from the ui for a branch


jobs:
test:
Expand Down Expand Up @@ -35,6 +36,9 @@ jobs:
- name: Run rspec tests
run: |
xvfb-run -a node ./out/test/runRspecTests.js
- name: Run parallel tests
run: |
xvfb-run -a node ./out/test/runParallelRspecTests.js
- name: Run Ruby test
run: |
cd ruby && bundle exec rake
17 changes: 15 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/src"
]
"${workspaceFolder}/out/**/*.js"
Copy link
Author

Choose a reason for hiding this comment

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

I found this helped the debugger correctly pick up break points, guess it meant source maps where available but not sure

],
"preLaunchTask": "npm: watch"
},
{
"name": "Run tests for Minitest",
Expand All @@ -36,6 +37,18 @@
"${workspaceFolder}/test/fixtures/rspec"
],
"outFiles": ["${workspaceFolder}/out/test/**/**/*.js"]
},
{
"name": "Run tests for Parallel RSpec",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/frameworks/rspec/index",
"${workspaceFolder}/test/fixtures/parallel_rspec"
],
"outFiles": ["${workspaceFolder}/out/test/**/**/*.js"]
}
]
}
1 change: 1 addition & 0 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ set -vx
npm install
bundle install --gemfile=ruby/Gemfile
bundle install --gemfile=test/fixtures/rspec/Gemfile
bundle install --gemfile=test/fixtures/parallel_rspec/Gemfile
bundle install --gemfile=test/fixtures/minitest/Gemfile
12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@
"type": "string",
"scope": "resource"
},
"rubyTestExplorer.useParallelRspec": {
"markdownDescription": "Use parallel rspec to run tests.",
"default": false,
"type": "boolean",
"scope": "resource"
},
"rubyTestExplorer.parallelRspecCommand": {
"markdownDescription": "Define the command to run parallel rspec tests with, for example `bundle exec parallel_rspec`.",
"default": "bundle exec parallel_rspec",
"type": "string",
"scope": "resource"
},
"rubyTestExplorer.rspecDirectory": {
"markdownDescription": "The location of your RSpec directory relative to the root of the workspace.",
"default": "./spec/",
Expand Down
23 changes: 23 additions & 0 deletions src/rspecTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,26 @@ export class RspecTests extends Tests {
return cmd
}

/**
* Get test command with formatter and debugger arguments
*
* @param debuggerConfig A VS Code debugger configuration.
* @return The test command
*/
protected parallelTestCommandWithFormatter(debuggerConfig?: vscode.DebugConfiguration): string {
let args = `--test-options "--require ${this.getCustomFormatterLocation()} --format CustomFormatter"`
return `${this.getParallelTestCommand()} ${args}`
}
/**
* Get the user-configured parallel RSpec command, if there is one.
*
* @return The RSpec command
*/
protected getParallelTestCommand(): string {
let command: string = (vscode.workspace.getConfiguration('rubyTestExplorer', null).get('parallelRspecCommand') as string);
return command || `bundle exec parallel_rspec`
}

/**
* Get the env vars to run the subprocess with.
*
Expand Down Expand Up @@ -221,6 +241,9 @@ export class RspecTests extends Tests {
};

let testCommand = this.testCommandWithFormatterAndDebugger(debuggerConfig);
if (vscode.workspace.getConfiguration('rubyTestExplorer', null).get('useParallelRspec') as boolean) {
testCommand = this.parallelTestCommandWithFormatter();
}
this.log.info(`Running command: ${testCommand}`);

let testProcess = childProcess.spawn(
Expand Down
10 changes: 10 additions & 0 deletions src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,15 @@ export abstract class Tests {
*/
handleChildProcess = async (process: childProcess.ChildProcess) => new Promise<string>((resolve, reject) => {
this.currentChildProcess = process;
let joinedJsonData = { examples: [] };

this.currentChildProcess.on('exit', () => {
this.log.info('Child process has exited. Sending test run finish event.');
this.currentChildProcess = undefined;
this.testStatesEmitter.fire(<TestRunFinishedEvent>{ type: 'finished' });
if (vscode.workspace.getConfiguration('rubyTestExplorer', null).get('useParallelRspec') as boolean) {
resolve('START_OF_TEST_JSON' + JSON.stringify(joinedJsonData) + 'END_OF_TEST_JSON');
}
resolve('{}');
});

Expand All @@ -371,6 +375,7 @@ export abstract class Tests {
}
});


this.currentChildProcess.stdout!.pipe(split2()).on('data', (data) => {
data = data.toString();
this.log.debug(`[CHILD PROCESS OUTPUT] ${data}`);
Expand All @@ -388,6 +393,11 @@ export abstract class Tests {
this.testStatesEmitter.fire(<TestEvent>{ type: 'test', test: data, state: 'skipped' });
}
if (data.includes('START_OF_TEST_JSON')) {
if (vscode.workspace.getConfiguration('rubyTestExplorer', null).get('useParallelRspec') as boolean) {
let parsedJson = JSON.parse(Tests.getJsonFromOutput(data));
joinedJsonData.examples = joinedJsonData.examples.concat(parsedJson.examples);
return;
}
resolve(data);
}
});
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/parallel_rspec/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source "https://rubygems.org"

gem "rspec"
gem "rake"
gem "parallel_tests"
32 changes: 32 additions & 0 deletions test/fixtures/parallel_rspec/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.4.4)
parallel (1.23.0)
parallel_tests (4.2.1)
parallel
rake (13.0.3)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-support (3.10.2)

PLATFORMS
ruby

DEPENDENCIES
parallel_tests
rake
rspec

BUNDLED WITH
2.4.13
Empty file.
10 changes: 10 additions & 0 deletions test/fixtures/parallel_rspec/lib/abs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Abs
def apply(n)
case
when n > 0
n
when n == 0
raise "Abs for zero is not supported"
end
end
end
5 changes: 5 additions & 0 deletions test/fixtures/parallel_rspec/lib/square.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Square
def apply(n)
n + n
end
end
17 changes: 17 additions & 0 deletions test/fixtures/parallel_rspec/spec/abs_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require "test_helper"

describe Abs do
it "finds the absolute value of 1" do
expect(Abs.new.apply(1)).to eq(1)
end

it "finds the absolute value of 0" do
expect(Abs.new.apply(0)).to eq(0)
end

it "finds the absolute value of -1" do
skip
expect(Abs.new.apply(-1)).to eq(1)
end
end

12 changes: 12 additions & 0 deletions test/fixtures/parallel_rspec/spec/square_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require "test_helper"

describe Square do
it "finds the square of 2" do
expect(Square.new.apply(2)).to eq(4)
end

it "finds the square of 3" do
expect(Square.new.apply(3)).to eq(9)
end
end

5 changes: 5 additions & 0 deletions test/fixtures/parallel_rspec/spec/test_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$LOAD_PATH << File.join(__dir__, "../lib")

require "abs"
require "square"
require "rspec"
32 changes: 32 additions & 0 deletions test/runParallelRspecTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as path from 'path';
import * as cp from 'child_process';

import { runTests, downloadAndUnzipVSCode, resolveCliPathFromVSCodeExecutablePath } from 'vscode-test';

async function main() {
try {
const extensionDevelopmentPath = path.resolve(__dirname, '../../');

const vscodeExecutablePath = await downloadAndUnzipVSCode('stable')

const cliPath = resolveCliPathFromVSCodeExecutablePath(vscodeExecutablePath)
cp.spawnSync(cliPath, ['--install-extension', 'hbenl.vscode-test-explorer'], {
encoding: 'utf-8',
stdio: 'inherit'
})

await runTests(
{
extensionDevelopmentPath,
extensionTestsPath: path.resolve(__dirname, './suite/frameworks/parallel_rspec/index'),
launchArgs: [path.resolve(extensionDevelopmentPath, 'test/fixtures/parallel_rspec')]
}
);
} catch (err) {
console.error(err);
console.error('Failed to run tests');
// process.exit(1);
}
}

main();
34 changes: 34 additions & 0 deletions test/suite/frameworks/parallel_rspec/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as path from 'path';
import * as Mocha from 'mocha';
import * as glob from 'glob';

export function run(): Promise<void> {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd'
});

return new Promise((c, e) => {
glob('**.test.js', { cwd: __dirname }, (err, files) => {
if (err) {
return e(err);
}

// Add files to the test suite
files.forEach(f => mocha.addFile(path.resolve(__dirname, f)));

try {
// Run the mocha test
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
e(err);
}
});
});
}
Loading