Skip to content

Commit 81bfd15

Browse files
committed
Add parallel test execution to CI pipeline
Configure parallel test execution to speed up CI builds and local test runs. ## Changes - Add parallel_tests gem for running tests concurrently - Configure database.yml to support TEST_ENV_NUMBER for parallel databases - Update GitHub Actions workflow to run tests across 4 parallel runners - Configure SimpleCov to merge coverage results from parallel runs ## Local Usage Run tests in parallel with 4 processes: ``` bundle exec parallel_rspec spec/ -n 4 ``` Run with a specific seed: ``` bundle exec parallel_rspec spec/ -n 4 -o '--seed 1234' ``` One-time setup (creates test, test2, test3, test4 databases): ``` bundle exec rake parallel:setup ``` ## Performance Local verification shows 1.84x speedup (162s → 88s) with identical coverage results (95.19%). Expected similar speedup in CI.
1 parent 197c40e commit 81bfd15

5 files changed

Lines changed: 72 additions & 13 deletions

File tree

.github/workflows/ruby.yml

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,26 @@ on: [ push, pull_request ]
44

55
jobs:
66
test:
7-
name: 'Tests'
7+
name: 'Tests (Group ${{ matrix.ci_node_index }})'
88
runs-on: ubuntu-latest
9+
strategy:
10+
fail-fast: false
11+
matrix:
12+
ci_node_total: [4]
13+
ci_node_index: [0, 1, 2, 3]
914

1015
env:
1116
# prevent unnecessary log output -- https://bundler.io/man/bundle-config.1.html
1217
BUNDLE_IGNORE_FUNDING_REQUESTS: true
1318
BUNDLE_IGNORE_MESSAGES: true
19+
RAILS_ENV: test
20+
PARALLEL_TEST_PROCESSORS: ${{ matrix.ci_node_total }}
1421
services:
1522
postgres:
1623
image: postgres:17
1724
ports: ["5432:5432"]
1825
env:
1926
POSTGRES_PASSWORD: postgres
20-
POSTGRES_DB: test
2127
options: >-
2228
--health-cmd pg_isready
2329
--health-interval 10s
@@ -34,20 +40,64 @@ jobs:
3440
# .ruby-version provides the Ruby version implicitly.
3541
bundler-cache: true
3642

37-
- name: Setup test database
43+
- name: Setup test databases
3844
env:
39-
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
40-
RAILS_ENV: test
41-
run:
42-
bundle exec rake db:create db:migrate
45+
DATABASE_URL: postgres://postgres:postgres@localhost:5432
46+
run: |
47+
bundle exec rake parallel:setup
4348
44-
- name: Run tests
49+
- name: Run tests in parallel
4550
env:
46-
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
47-
RAILS_ENV: test
48-
run: bundle exec rake spec
51+
DATABASE_URL: postgres://postgres:postgres@localhost:5432
52+
TEST_ENV_NUMBER: ${{ matrix.ci_node_index }}
53+
run: |
54+
bundle exec parallel_rspec spec/ \
55+
-n ${{ matrix.ci_node_total }} \
56+
--only-group ${{ matrix.ci_node_index }}
57+
58+
- name: Upload coverage artifacts
59+
uses: actions/upload-artifact@v4
60+
with:
61+
name: coverage-${{ matrix.ci_node_index }}
62+
path: coverage/.resultset.json
63+
retention-days: 1
64+
65+
coverage:
66+
name: 'Report Coverage'
67+
runs-on: ubuntu-latest
68+
needs: test
69+
steps:
70+
- name: Checkout code
71+
uses: actions/checkout@v6
72+
73+
- name: Set up Ruby
74+
uses: ruby/setup-ruby@v1
75+
with:
76+
bundler-cache: true
77+
78+
- name: Download all coverage artifacts
79+
uses: actions/download-artifact@v4
80+
with:
81+
path: coverage-results
82+
83+
- name: Merge coverage results
84+
run: |
85+
mkdir -p coverage
86+
bundle exec ruby -e '
87+
require "json"
88+
require "simplecov"
89+
90+
resultsets = {}
91+
Dir["coverage-results/coverage-*/.resultset.json"].each do |file|
92+
data = JSON.parse(File.read(file))
93+
resultsets.merge!(data)
94+
end
95+
96+
File.write("coverage/.resultset.json", JSON.generate(resultsets))
97+
'
98+
4999
- name: Report to Coveralls
50-
continue-on-error: true # Don't fail the build if Coveralls fails to upload.
100+
continue-on-error: true
51101
uses: coverallsapp/github-action@v2
52102
with:
53103
github-token: ${{ secrets.github_token }}

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ group :development, :test do
9090
gem 'faker'
9191
gem 'irb' # LOCKED: Added because of byebug
9292
gem 'launchy'
93+
gem 'parallel_tests'
9394
gem 'pry-rails'
9495
gem 'pry-byebug'
9596
gem 'pry-remote'

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ GEM
338338
json
339339
yaml
340340
parallel (1.27.0)
341+
parallel_tests (5.5.0)
342+
parallel
341343
parser (3.3.10.1)
342344
ast (~> 2.4.1)
343345
racc
@@ -651,6 +653,7 @@ DEPENDENCIES
651653
omniauth-github
652654
omniauth-rails_csrf_protection
653655
pagy (~> 43.2)
656+
parallel_tests
654657
pg
655658
pickadate-rails
656659
premailer-rails

config/database.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ development: &default
99

1010
test:
1111
<<: *default
12-
database: planner_test
12+
database: planner_test<%= ENV['TEST_ENV_NUMBER'] %>
1313
pool: 5

spec/spec_helper.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ def self.branch_coverage?
2828

2929
SimpleCov.start do
3030
add_filter 'spec/'
31+
32+
# Support parallel test execution
33+
if ENV['TEST_ENV_NUMBER']
34+
command_name "RSpec-#{ENV['TEST_ENV_NUMBER']}"
35+
end
3136
end
3237

3338
ENV['RAILS_ENV'] ||= 'test'

0 commit comments

Comments
 (0)