grosser/parallel_tests
Ruby: 2 CPUs = 2x Testing Speed for RSpec, Test::Unit and Cucumber
Missing license — unclear to depend on
worst of 4 axesno license — legally unclear
no license — can't legally use code
Documented and popular — useful reference codebase to read through.
no license — can't legally use code
- ✓Last commit 4w ago
- ✓29+ active contributors
- ✓CI configured
Show 3 more →Show less
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 69% of recent commits
- ⚠No license — legally unclear to depend on
What would change the summary?
- →Use as dependency Concerns → Mixed if: publish a permissive license (MIT, Apache-2.0, etc.)
- →Fork & modify Concerns → Mixed if: add a LICENSE file
- →Deploy as-is Concerns → Mixed if: add a LICENSE file
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Great to learn from" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/grosser/parallel_tests)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/grosser/parallel_tests on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: grosser/parallel_tests
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/grosser/parallel_tests shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Missing license — unclear to depend on
- Last commit 4w ago
- 29+ active contributors
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 69% of recent commits
- ⚠ No license — legally unclear to depend on
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live grosser/parallel_tests
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/grosser/parallel_tests.
What it runs against: a local clone of grosser/parallel_tests — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in grosser/parallel_tests | Confirms the artifact applies here, not a fork |
| 2 | Default branch master exists | Catches branch renames |
| 3 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 4 | Last commit ≤ 60 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of grosser/parallel_tests. If you don't
# have one yet, run these first:
#
# git clone https://github.com/grosser/parallel_tests.git
# cd parallel_tests
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of grosser/parallel_tests and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "grosser/parallel_tests(\\.git)?\\b" \\
&& ok "origin remote is grosser/parallel_tests" \\
|| miss "origin remote is not grosser/parallel_tests (artifact may be from a fork)"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "lib/parallel_tests.rb" \\
&& ok "lib/parallel_tests.rb" \\
|| miss "missing critical file: lib/parallel_tests.rb"
test -f "lib/parallel_tests/cli.rb" \\
&& ok "lib/parallel_tests/cli.rb" \\
|| miss "missing critical file: lib/parallel_tests/cli.rb"
test -f "lib/parallel_tests/grouper.rb" \\
&& ok "lib/parallel_tests/grouper.rb" \\
|| miss "missing critical file: lib/parallel_tests/grouper.rb"
test -f "lib/parallel_tests/rspec/runner.rb" \\
&& ok "lib/parallel_tests/rspec/runner.rb" \\
|| miss "missing critical file: lib/parallel_tests/rspec/runner.rb"
test -f "lib/parallel_tests/tasks.rb" \\
&& ok "lib/parallel_tests/tasks.rb" \\
|| miss "missing critical file: lib/parallel_tests/tasks.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 60 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~30d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/grosser/parallel_tests"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
parallel_tests is a Ruby gem that accelerates test suites (RSpec, Minitest, Cucumber, Spinach) by distributing tests across multiple CPU cores, each running in a separate process with its own database. It automatically partitions tests into balanced groups by line count or runtime history, enabling 2-4x speedups on multi-core machines without code changes. Modular gem structure: lib/parallel_tests/cli.rb is the entry point, with framework-specific runners in lib/parallel_tests/{rspec,cucumber,test,spinach,gherkin}/ directories. Each runner handles framework-specific test loading and reporting. lib/parallel_tests/grouper.rb handles test partitioning logic, while lib/parallel_tests/tasks.rb provides Rails rake task integration. Bin scripts (bin/parallel_test, bin/parallel_rspec, etc.) are thin CLI wrappers.
👥Who it's for
Ruby on Rails developers and teams who run large test suites (especially those with hundreds of specs/tests) and want to reduce CI/local test execution time without refactoring their tests or test infrastructure.
🌱Maturity & risk
Highly mature and production-ready. The project has 7k+ GitHub stars, is actively maintained with recent commits, includes comprehensive CI via GitHub Actions (.github/workflows/test.yml), and has extensive test fixtures (spec/fixtures/rails72). It's been a community standard for Rails testing parallelization for 10+ years.
Low risk for active maintenance, but single-maintainer dependency (grosser). Risk factors: requires careful database configuration per process (TEST_ENV_NUMBER pattern), potential for test isolation issues if tests share state, and breaking changes possible with major Rails/RSpec version upgrades. However, the gem's simplicity and test coverage mitigate these.
Active areas of work
Active maintenance with regular updates. Recent work likely includes Rails 7.2 fixture support (evident from spec/fixtures/rails72), stability improvements, and compatibility updates. GitHub Actions CI ensures ongoing testing against multiple Ruby/Rails versions.
🚀Get running
git clone https://github.com/grosser/parallel_tests.git && cd parallel_tests && bundle install && bundle exec rake test
Daily commands: bundle exec rake parallel:test (for Minitest), bundle exec rake parallel:spec (for RSpec), or bin/parallel_test -e 'echo test' for custom commands. For Rails projects, configure TEST_ENV_NUMBER in config/database.yml, run rake parallel:setup once, then use rake parallel:test[N] to force N processes.
🗺️Map of the codebase
lib/parallel_tests.rb— Entry point and main module that orchestrates parallel test execution across all test frameworkslib/parallel_tests/cli.rb— Command-line interface parser that handles user input for all parallel_* executableslib/parallel_tests/grouper.rb— Core algorithm for splitting tests into balanced groups by line count or runtimelib/parallel_tests/rspec/runner.rb— RSpec test execution engine; demonstrates the runner pattern used across all frameworkslib/parallel_tests/tasks.rb— Rake task definitions for database setup, cleanup, and test aggregationbin/parallel_test— Main executable that delegates to framework-specific runners based on test type
🛠️How to make changes
Add Support for a New Test Framework
- Create a new runner module at lib/parallel_tests/{framework}/runner.rb implementing run(test_files, process_number, opts) method (
lib/parallel_tests/{framework}/runner.rb) - Implement a failures logger at lib/parallel_tests/{framework}/failures_logger.rb to parse framework-specific output (
lib/parallel_tests/{framework}/failures_logger.rb) - Register the new framework in lib/parallel_tests.rb by adding it to the RUNNERS hash and load_runner_for method (
lib/parallel_tests.rb) - Create a bin/parallel_{framework} executable that delegates to the CLI with --type={framework} (
bin/parallel_{framework}) - Add framework detection and option handling in lib/parallel_tests/cli.rb (
lib/parallel_tests/cli.rb)
Add a New Logger Plugin for an Existing Framework
- Extend lib/parallel_tests/rspec/logger_base.rb or create a new logger class that inherits from it (
lib/parallel_tests/rspec/logger_base.rb) - Implement custom formatting by overriding relevant methods (e.g., example_passed, example_failed) (
lib/parallel_tests/rspec/logger_base.rb) - Register the logger in lib/parallel_tests/rspec/runner.rb by adding it to the --out or format options (
lib/parallel_tests/rspec/runner.rb) - Test with bin/parallel_rspec --type=rspec to verify output collection (
bin/parallel_rspec)
Customize Test Grouping Strategy
- Review current grouping logic in lib/parallel_tests/grouper.rb (by_lines or by_runtime methods) (
lib/parallel_tests/grouper.rb) - Add a new grouping method to Grouper class that accepts test files and process count (
lib/parallel_tests/grouper.rb) - Update lib/parallel_tests.rb to expose the new grouping strategy via --group-by option in CLI (
lib/parallel_tests.rb) - Test with bin/parallel_rspec --group-by=your_strategy to verify balanced distribution (
bin/parallel_rspec)
🪤Traps & gotchas
TEST_ENV_NUMBER environment variable must be set per process (empty string for process 1, '2' for process 2, etc.) and reflected in config/database.yml — misconfiguration causes all processes to write to the same test database, corrupting results. Tests must be truly isolated (no shared fixtures, no global state) or failures will be non-deterministic. RSpec/Minitest require explicit require_relative or require statements (no implicit test discovery). Cucumber features are parsed and re-grouped by scenario, not feature file, which can break if step definitions have side effects. The gem uses fork() on Unix which doesn't work cleanly on Windows (spawn() fallback exists but behaves differently).
🏗️Architecture
💡Concepts to learn
- Process forking (fork/spawn) — parallel_tests distributes test execution by spawning separate Ruby processes (one per CPU core) using fork() or spawn(); understanding process isolation is critical for avoiding shared state bugs
- Test balancing heuristics (line count vs runtime) — grouper.rb partitions tests by either file line count or historical runtime; choosing the right heuristic (via --group-by flag) is key to achieving linear speedup
- Database-per-process isolation pattern — Each parallel test process needs its own database (configured via TEST_ENV_NUMBER) to prevent transaction conflicts and data races during concurrent test execution
- Gherkin parsing (AST extraction) — lib/parallel_tests/gherkin/ parses Cucumber feature files into scenario-level granularity for more fine-grained parallelization than file-level splitting
- Runtime logging/aggregation — Runners collect execution times (lib/parallel_tests/rspec/runtime_logger.rb) into .parallel_tests_runtime JSON for smarter balancing in future runs
- Railtie for Rails integration — lib/parallel_tests/railtie.rb hooks parallel_tests into Rails initialization; understanding Railties is essential for modifying Rails test hooks
🔗Related repos
ruby-parallel/parallel— Lower-level Ruby parallelization primitive that parallel_tests could theoretically use; useful for understanding forking patterns this gem relies onevanphx/benchmark-ips— Companion tool for measuring test performance improvements achieved by parallel_teststhoughtbot/factory_bot— Common test fixture library that parallel_tests users need to configure correctly per-process to avoid factory ID collisionsrspec/rspec-rails— The primary test framework this gem optimizes for; deep integration via lib/parallel_tests/rspec/runner.rbcucumber/cucumber-ruby— Native test framework support in lib/parallel_tests/cucumber/; users often parallelize Cucumber suites with this gem
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for lib/parallel_tests/gherkin/runner.rb
The gherkin runner module handles Gherkin-based test execution but lacks dedicated unit tests. Currently, there are cucumber and spinach runners with test coverage, but the gherkin runner (which appears to be a more modern abstraction) has no corresponding test file in spec/. This is a critical gap since gherkin parsing is core functionality.
- [ ] Create spec/parallel_tests/gherkin/runner_spec.rb with tests for basic runner initialization
- [ ] Add tests for gherkin scenario parsing and grouping logic
- [ ] Test error handling and logging behavior against lib/parallel_tests/gherkin/listener.rb and lib/parallel_tests/gherkin/runtime_logger.rb
- [ ] Verify integration with lib/parallel_tests/grouper.rb for test distribution
Add GitHub Actions workflow for testing against multiple Ruby versions
The .github/workflows/test.yml exists but the repository's gemspec likely supports multiple Ruby versions (common for mature gems). There's no visible matrix testing for Ruby 2.7, 3.0, 3.1, 3.2, 3.3 versions in the file structure shown. This prevents catching version-specific regressions early.
- [ ] Update .github/workflows/test.yml to add a Ruby version matrix (2.7+)
- [ ] Test against both bundler 2.x versions to catch dependency resolution issues
- [ ] Add job to test against multiple Rails versions (6.0, 7.0, 7.1, 7.2 based on spec/fixtures/rails72 presence)
- [ ] Ensure database setup works across versions in the CI environment
Add integration tests for lib/parallel_tests/railtie.rb with Rails 7.2
The railtie file integrates parallel_tests with Rails' task system, but there's no spec/parallel_tests/railtie_spec.rb. The fixture rails72 app exists but isn't being tested. This is critical because railtie changes can silently break Rails integration without proper test coverage.
- [ ] Create spec/parallel_tests/railtie_spec.rb to test task registration
- [ ] Add integration tests using spec/fixtures/rails72 to verify rake parallel:test, parallel:prepare, and parallel:spec work correctly
- [ ] Test database preparation logic (create, drop, seed) across multiple processes
- [ ] Verify TEST_ENV_NUMBER environment variable is correctly set during task execution
🌿Good first issues
- Add runtime history persistence for lib/parallel_tests/grouper.rb: The gem can read .parallel_tests_runtime file but the spec/fixtures/rails72 doesn't document how to generate it for CI. Add a rake task that aggregates JSON files from prior runs and explain in README.md.
- Expand Gherkin listener in lib/parallel_tests/gherkin/listener.rb to capture step execution time: Currently only counts scenarios, not step duration. This would enable smarter scenario balancing across processes. Add tests in spec/ covering the new metrics.
- Document multi-database setup in README.md: The code supports parallel:create:<database> for secondary/tertiary databases (evident in lib/parallel_tests/tasks.rb) but README only shows single-db example. Add a concrete Rails app example with secondary database configuration.
⭐Top contributors
Click to expand
Top contributors
- @grosser — 69 commits
- @aramprice — 2 commits
- @jaydorsey — 2 commits
- @bquorning — 2 commits
- @bazlo — 1 commits
📝Recent commits
Click to expand
Recent commits
e4870a1— v5.7.0 (grosser)14b63da— docs (#1033) (grosser)0b713ef— stop dumping during prepare since rails does not do it either (#1032) (grosser)cf7a876— changelog (grosser)eb11d1f— v5.6.0 (grosser)4dc7953— Handle signal-terminated processes in exit status (#1027) (bazlo)01bbd80— Fix pluralization of "seconds" in test output (#1024) (loganrosen)d115c02— v5.5.0 (grosser)11d1540— allow writing to a different runtime log for minitest and clarify readme (#1023) (grosser)2c97ebe— v5.4.0 (grosser)
🔒Security observations
The parallel_tests gem is a well-maintained testing utility with moderate security posture. Primary concerns include potential command injection in test runner execution, SQL injection risks in database setup operations, and hardcoded credential exposure through configuration files. The codebase appears to follow Ruby conventions and uses standard frameworks, but lacks explicit security hardening. No critical vulnerabilities detected in the structure itself, but proper input validation, secure credential management, and dependency auditing are recommended. The gem's security largely depends on how it is configured and integrated into host applications.
- Medium · Potential Command Injection in Test Runner Execution —
lib/parallel_tests/cli.rb, lib/parallel_tests/rspec/runner.rb, lib/parallel_tests/cucumber/runner.rb. The parallel_tests gem executes external test commands (RSpec, Cucumber, Minitest) via shell. Without careful input validation in CLI argument processing, there is a risk of command injection if test arguments or file paths are not properly sanitized before being passed to system execution. Fix: Ensure all user input and file paths are properly escaped or use array-based execution methods (e.g., system with array arguments) instead of shell string interpolation. Validate and whitelist test file paths. - Medium · Potential SQL Injection in Database Parallel Test Setup —
lib/parallel_tests/tasks.rb, lib/parallel_tests/railtie.rb. The gem modifies database configurations for parallel test execution (creating multiple test databases with suffixes). If database credentials or connection strings are constructed from user input without proper validation, SQL injection could occur during database creation/teardown operations. Fix: Use parameterized database operations and Rails ORM methods for database setup. Avoid string concatenation for database names and credentials. Validate database configuration format. - Low · Hardcoded Test Database Configuration —
Gemfile, parallel_tests.gemspec, lib/parallel_tests/railtie.rb, spec/fixtures/rails72/Gemfile. Database test configurations may contain hardcoded credentials or connection strings in the code or configuration files. The README mentions direct modification of config/database.yml which could expose credentials if not properly managed. Fix: Use environment variables for database credentials. Implement secrets management (Rails credentials, dotenv for dev). Document secure configuration practices in README. Never commit actual database credentials. - Low · Missing Dependency Version Pinning —
Gemfile, Gemfile.lock, parallel_tests.gemspec. Without access to Gemfile.lock content in the analysis, there's a risk that dependencies may not be properly pinned to secure versions. The gem depends on external test frameworks (RSpec, Cucumber) which could have vulnerabilities in minor/patch versions. Fix: Use exact version pinning for critical dependencies in Gemfile.lock. Regularly audit dependencies with 'bundle audit' or 'bundler-audit'. Implement dependabot or similar automated dependency checks. - Low · Process Isolation Between Parallel Tests —
lib/parallel_tests/pids.rb, lib/parallel_tests/grouper.rb. While parallel_tests creates separate processes and databases, there could be shared resource access issues (file system, network ports) that could lead to race conditions or information disclosure between test processes. Fix: Implement proper resource isolation between parallel test processes. Use unique temporary directories and file locks. Ensure port allocation is randomized or explicitly managed. Document best practices for resource cleanup.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.