rspec-conductor 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +25 -1
- data/lib/rspec/conductor/cli.rb +2 -2
- data/lib/rspec/conductor/server.rb +2 -2
- data/lib/rspec/conductor/util/ansi.rb +12 -6
- data/lib/rspec/conductor/version.rb +1 -1
- data/lib/rspec/conductor.rb +25 -12
- data/lib/tasks/rspec_conductor.rake +24 -23
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 880d64a3a408ec26218ffc3d108ef6aa12b14da3a6f8d6b5e6ad5d8599373e0b
|
|
4
|
+
data.tar.gz: 421c5c55606788739b895d559d6093032454a831f47a18e5d5a616b76d0ccf49
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2102903198e4025159240b0a3c564831e3a10db533eef4cb1811d5bc20b6122fe10cf7e856a3a523c2bad2076772cd5da848a66a3cb3e6f6d0f93244a0477c3e
|
|
7
|
+
data.tar.gz: abbaf107a50db30d9ad2e8e87c27dd3188c7afbcd2714ce37a8aef56bf88cc6fdbcb25471c6497137c0e5a5cb15a0cdb53e4516a73f2ccbd7e4055268951ec02
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.0.4] - 2026-02-12
|
|
2
|
+
|
|
3
|
+
- use Etc.nprocessors to determine the default worker count (reported by @coorasse)
|
|
4
|
+
- use env vars (RSPEC_CONDUCTOR_DEFAULT_WORKER_COUNT, RSPEC_CONDUCTOR_FIRST_IS_1) more consistently between the rake task and the cli. Meaning, if you set these env vars, you should also see the corresponding change in the cli defaults
|
|
5
|
+
- Fix some rake task issues in CI (reported by @cb341)
|
|
6
|
+
- Fix namespace clash with RSpec::Rails in the rake task (reported by @cb341)
|
|
7
|
+
|
|
1
8
|
## [1.0.3] - 2026-02-08
|
|
2
9
|
|
|
3
10
|
- rake tasks for database preparation
|
data/README.md
CHANGED
|
@@ -37,7 +37,18 @@ Server process preloads the `rails_helper`, prepares a list of files to work, th
|
|
|
37
37
|
|
|
38
38
|
## Setting up the databases in Rails
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
If you want ten workers, you're going to need ten databases. Something like this in your `database.yml` file:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
test:
|
|
44
|
+
primary:
|
|
45
|
+
<<: *default
|
|
46
|
+
database: database_test<%= ENV['TEST_ENV_NUMBER'] %>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
That means worker number 3 is going to use database `database_test3`, worker number 4 `database_test4` and so on. Worker number 1 is special: with `--first-is-1` flag on it uses `TEST_ENV_NUMBER="1"`, but without it, it uses `TEST_ENV_NUMBER=""` (empty string).
|
|
50
|
+
|
|
51
|
+
In order to bootstrap the test databases, there is a rake task:
|
|
41
52
|
|
|
42
53
|
```bash
|
|
43
54
|
# Recreate and seed test databases with TEST_ENV_NUMBER 1 to 10
|
|
@@ -49,6 +60,12 @@ RSPEC_CONDUCTOR_FIRST_IS_1=1 rails rspec_conductor:setup[10]
|
|
|
49
60
|
|
|
50
61
|
You can also set the env variable `RSPEC_CONDUCTOR_DEFAULT_WORKER_COUNT` to change the default worker count to avoid typing the quotes for the rake task arguments in zsh.
|
|
51
62
|
|
|
63
|
+
```bash
|
|
64
|
+
export RSPEC_CONDUCTOR_DEFAULT_WORKER_COUNT=10
|
|
65
|
+
rails rspec_conductor:setup # assumes [10]
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
|
|
52
69
|
## Development notes
|
|
53
70
|
|
|
54
71
|
* In order to make the CLI executable load and run fast, do not add any dependencies. That includes `active_support`.
|
|
@@ -72,6 +89,13 @@ Short answer: it's unsafe. Any file descriptors, such as db connections, redis c
|
|
|
72
89
|
|
|
73
90
|
## Prior Art
|
|
74
91
|
|
|
92
|
+
### File-based runners (split the load before the launch)
|
|
93
|
+
|
|
94
|
+
* [parallel-tests](https://github.com/grosser/parallel_tests)
|
|
95
|
+
* [flatware](https://github.com/briandunn/flatware)
|
|
96
|
+
|
|
97
|
+
### Queue-based runners (feed workers from the queue)
|
|
98
|
+
|
|
75
99
|
* [test-queue](https://github.com/tmm1/test-queue)
|
|
76
100
|
* [rspecq](https://github.com/skroutz/rspecq/)
|
|
77
101
|
* [ci-queue](https://github.com/Shopify/ci-queue/)
|
data/lib/rspec/conductor/cli.rb
CHANGED
|
@@ -26,7 +26,7 @@ module RSpec
|
|
|
26
26
|
@worker_number_offset = opts.fetch(:worker_number_offset, 0)
|
|
27
27
|
@prefork_require = opts.fetch(:prefork_require, nil)
|
|
28
28
|
@postfork_require = opts.fetch(:postfork_require, nil)
|
|
29
|
-
@
|
|
29
|
+
@first_is_1 = opts.fetch(:first_is_1, Conductor.default_first_is_1?)
|
|
30
30
|
@seed = opts[:seed] || (Random.new_seed % MAX_SEED)
|
|
31
31
|
@fail_fast_after = opts[:fail_fast_after]
|
|
32
32
|
@display_retry_backtraces = opts.fetch(:display_retry_backtraces, false)
|
|
@@ -134,7 +134,7 @@ module RSpec
|
|
|
134
134
|
pid = fork do
|
|
135
135
|
parent_socket.close
|
|
136
136
|
|
|
137
|
-
ENV["TEST_ENV_NUMBER"] = if @
|
|
137
|
+
ENV["TEST_ENV_NUMBER"] = if @first_is_1 || worker_number != 1
|
|
138
138
|
worker_number.to_s
|
|
139
139
|
else
|
|
140
140
|
""
|
|
@@ -122,16 +122,22 @@ module RSpec
|
|
|
122
122
|
string.gsub(ANSI_SEQUENCE_REGEX, '')
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
def tty_width(
|
|
126
|
-
return 80 unless
|
|
125
|
+
def tty_width(io = $stdout)
|
|
126
|
+
return 80 unless io.tty?
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
width = io.winsize[1].to_i
|
|
129
|
+
return 40 if width < 40 # work around some badly behaved ci environments
|
|
130
|
+
|
|
131
|
+
width
|
|
129
132
|
end
|
|
130
133
|
|
|
131
|
-
def tty_height(
|
|
132
|
-
return 50 unless
|
|
134
|
+
def tty_height(io = $stdout)
|
|
135
|
+
return 50 unless io.tty?
|
|
136
|
+
|
|
137
|
+
height = io.winsize[0].to_i
|
|
138
|
+
return 10 if height < 10 # work around some badly behaved ci environments
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
height
|
|
135
141
|
end
|
|
136
142
|
end
|
|
137
143
|
end
|
data/lib/rspec/conductor.rb
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rspec/core"
|
|
4
|
+
require "etc"
|
|
5
|
+
|
|
6
|
+
module RSpec
|
|
7
|
+
module Conductor
|
|
8
|
+
def self.root
|
|
9
|
+
@root ||= Dir.pwd
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.root=(root)
|
|
13
|
+
@root = root
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.default_worker_count
|
|
17
|
+
@default_worker_count ||= if ENV['RSPEC_CONDUCTOR_DEFAULT_WORKER_COUNT'].to_i > 0
|
|
18
|
+
ENV['RSPEC_CONDUCTOR_DEFAULT_WORKER_COUNT'].to_i
|
|
19
|
+
else
|
|
20
|
+
Etc.nprocessors
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.default_first_is_1?
|
|
25
|
+
ENV["RSPEC_CONDUCTOR_FIRST_IS_1"] == "1"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
4
29
|
|
|
5
30
|
require_relative "conductor/util/ansi"
|
|
6
31
|
require_relative "conductor/util/terminal"
|
|
@@ -16,18 +41,6 @@ require_relative "conductor/formatters/plain"
|
|
|
16
41
|
require_relative "conductor/formatters/ci"
|
|
17
42
|
require_relative "conductor/formatters/fancy"
|
|
18
43
|
|
|
19
|
-
module RSpec
|
|
20
|
-
module Conductor
|
|
21
|
-
def self.root
|
|
22
|
-
@root ||= Dir.pwd
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.root=(root)
|
|
26
|
-
@root = root
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
44
|
if defined?(Rails)
|
|
32
45
|
require_relative "conductor/railtie"
|
|
33
46
|
end
|
|
@@ -4,19 +4,15 @@ module RSpec
|
|
|
4
4
|
module Conductor
|
|
5
5
|
module DatabaseTasks
|
|
6
6
|
class << self
|
|
7
|
-
def default_worker_count
|
|
8
|
-
ENV['RSPEC_CONDUCTOR_DEFAULT_WORKER_COUNT']&.to_i || 4
|
|
9
|
-
end
|
|
10
|
-
|
|
11
7
|
def create_databases(count)
|
|
12
8
|
run_for_each_database(count, "Creating") do
|
|
13
|
-
db_configs.each { |config| ActiveRecord::Tasks::DatabaseTasks.create(config) }
|
|
9
|
+
db_configs.each { |config| ::ActiveRecord::Tasks::DatabaseTasks.create(config) }
|
|
14
10
|
end
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def drop_databases(count)
|
|
18
14
|
run_for_each_database(count, "Dropping") do
|
|
19
|
-
db_configs.each { |config| ActiveRecord::Tasks::DatabaseTasks.drop(config) }
|
|
15
|
+
db_configs.each { |config| ::ActiveRecord::Tasks::DatabaseTasks.drop(config) }
|
|
20
16
|
end
|
|
21
17
|
end
|
|
22
18
|
|
|
@@ -25,29 +21,29 @@ module RSpec
|
|
|
25
21
|
|
|
26
22
|
run_for_each_database(count, "Setting up") do
|
|
27
23
|
puts "Dropping database(s)"
|
|
28
|
-
db_configs.each { |config| ActiveRecord::Tasks::DatabaseTasks.drop(config) }
|
|
24
|
+
db_configs.each { |config| ::ActiveRecord::Tasks::DatabaseTasks.drop(config) }
|
|
29
25
|
|
|
30
26
|
puts "Creating database(s)"
|
|
31
|
-
db_configs.each { |config| ActiveRecord::Tasks::DatabaseTasks.create(config) }
|
|
27
|
+
db_configs.each { |config| ::ActiveRecord::Tasks::DatabaseTasks.create(config) }
|
|
32
28
|
|
|
33
29
|
puts "Loading schema"
|
|
34
|
-
db_configs.each { |config| ActiveRecord::Tasks::DatabaseTasks.load_schema(config, schema_format, schema_file) }
|
|
30
|
+
db_configs.each { |config| ::ActiveRecord::Tasks::DatabaseTasks.load_schema(config, schema_format, schema_file) }
|
|
35
31
|
|
|
36
32
|
puts "Loading seed"
|
|
37
|
-
ActiveRecord::Tasks::DatabaseTasks.load_seed
|
|
33
|
+
::ActiveRecord::Tasks::DatabaseTasks.load_seed
|
|
38
34
|
end
|
|
39
35
|
end
|
|
40
36
|
|
|
41
37
|
private
|
|
42
38
|
|
|
43
39
|
def first_is_1?
|
|
44
|
-
|
|
40
|
+
RSpec::Conductor.default_first_is_1?
|
|
45
41
|
end
|
|
46
42
|
|
|
47
43
|
def db_configs
|
|
48
44
|
reload_database_configuration!
|
|
49
45
|
|
|
50
|
-
configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
|
|
46
|
+
configs = ::ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
|
|
51
47
|
raise ArgumentError, "could not find or parse configuration for the env #{Rails.env}" unless configs.any?
|
|
52
48
|
|
|
53
49
|
configs
|
|
@@ -58,7 +54,7 @@ module RSpec
|
|
|
58
54
|
|
|
59
55
|
puts "#{action} #{count} test databases in parallel..."
|
|
60
56
|
# Close connections before forking to avoid sharing file descriptors
|
|
61
|
-
ActiveRecord::Base.connection_pool.disconnect!
|
|
57
|
+
::ActiveRecord::Base.connection_pool.disconnect!
|
|
62
58
|
|
|
63
59
|
terminal = Conductor::Util::Terminal.new
|
|
64
60
|
children = count.times.map do |i|
|
|
@@ -106,12 +102,12 @@ module RSpec
|
|
|
106
102
|
parsed_yaml = Rails.application.config.load_database_yaml
|
|
107
103
|
raise ArgumentError, "could not find database yaml or the yaml is empty" if parsed_yaml.empty?
|
|
108
104
|
|
|
109
|
-
ActiveRecord::Base.configurations = ActiveRecord::DatabaseConfigurations.new(parsed_yaml)
|
|
105
|
+
::ActiveRecord::Base.configurations = ::ActiveRecord::DatabaseConfigurations.new(parsed_yaml)
|
|
110
106
|
end
|
|
111
107
|
|
|
112
108
|
def schema_format_and_file
|
|
113
|
-
ruby_schema = File.join(Rails.root, "db", "schema.rb")
|
|
114
|
-
sql_schema = File.join(Rails.root, "db", "structure.sql")
|
|
109
|
+
ruby_schema = File.join(::Rails.root, "db", "schema.rb")
|
|
110
|
+
sql_schema = File.join(::Rails.root, "db", "structure.sql")
|
|
115
111
|
|
|
116
112
|
if File.exist?(ruby_schema)
|
|
117
113
|
[:ruby, ruby_schema]
|
|
@@ -127,21 +123,21 @@ module RSpec
|
|
|
127
123
|
end
|
|
128
124
|
|
|
129
125
|
namespace :rspec_conductor do
|
|
130
|
-
desc "Create parallel test databases (default: #{RSpec::Conductor
|
|
126
|
+
desc "Create parallel test databases (default: #{RSpec::Conductor.default_worker_count})"
|
|
131
127
|
task :create, [:count] => %w(set_rails_env_to_test environment) do |_t, args|
|
|
132
|
-
count = (args[:count] || RSpec::Conductor
|
|
128
|
+
count = (args[:count] || RSpec::Conductor.default_worker_count).to_i
|
|
133
129
|
RSpec::Conductor::DatabaseTasks.create_databases(count)
|
|
134
130
|
end
|
|
135
131
|
|
|
136
|
-
desc "Drop parallel test databases (default: #{RSpec::Conductor
|
|
132
|
+
desc "Drop parallel test databases (default: #{RSpec::Conductor.default_worker_count})"
|
|
137
133
|
task :drop, [:count] => %w(set_rails_env_to_test environment) do |_t, args|
|
|
138
|
-
count = (args[:count] || RSpec::Conductor
|
|
134
|
+
count = (args[:count] || RSpec::Conductor.default_worker_count).to_i
|
|
139
135
|
RSpec::Conductor::DatabaseTasks.drop_databases(count)
|
|
140
136
|
end
|
|
141
137
|
|
|
142
|
-
desc "Setup parallel test databases (drop + create + schema load + seed) (default: #{RSpec::Conductor
|
|
138
|
+
desc "Setup parallel test databases (drop + create + schema load + seed) (default: #{RSpec::Conductor.default_worker_count})"
|
|
143
139
|
task :setup, [:count] => %w(set_rails_env_to_test environment) do |_t, args|
|
|
144
|
-
count = (args[:count] || RSpec::Conductor
|
|
140
|
+
count = (args[:count] || RSpec::Conductor.default_worker_count).to_i
|
|
145
141
|
RSpec::Conductor::DatabaseTasks.setup_databases(count)
|
|
146
142
|
end
|
|
147
143
|
|
|
@@ -152,8 +148,13 @@ namespace :rspec_conductor do
|
|
|
152
148
|
if ENV['RAILS_ENV']
|
|
153
149
|
require_relative "../rspec/conductor/util/terminal"
|
|
154
150
|
require_relative "../rspec/conductor/util/child_process"
|
|
151
|
+
|
|
152
|
+
unless defined?(::Rails.root) && defined?(::ActiveRecord::Tasks::DatabaseTasks)
|
|
153
|
+
warn 'rspec-conductor rake tasks need a working rails environment to work with the databases'
|
|
154
|
+
exit 1
|
|
155
|
+
end
|
|
155
156
|
else
|
|
156
|
-
system({ "RAILS_ENV" => "test" }, "rake",
|
|
157
|
+
system({ "RAILS_ENV" => "test" }, "rake", *::Rake.application.top_level_tasks)
|
|
157
158
|
exit
|
|
158
159
|
end
|
|
159
160
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rspec-conductor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mark Abramov
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rspec-core
|
|
@@ -67,7 +66,6 @@ metadata:
|
|
|
67
66
|
homepage_uri: https://github.com/markiz/rspec-conductor
|
|
68
67
|
source_code_uri: https://github.com/markiz/rspec-conductor
|
|
69
68
|
changelog_uri: https://github.com/markiz/rspec-conductor/blob/master/CHANGELOG.md
|
|
70
|
-
post_install_message:
|
|
71
69
|
rdoc_options: []
|
|
72
70
|
require_paths:
|
|
73
71
|
- lib
|
|
@@ -82,8 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
82
80
|
- !ruby/object:Gem::Version
|
|
83
81
|
version: '0'
|
|
84
82
|
requirements: []
|
|
85
|
-
rubygems_version:
|
|
86
|
-
signing_key:
|
|
83
|
+
rubygems_version: 4.0.3
|
|
87
84
|
specification_version: 4
|
|
88
85
|
summary: Queue-based parallel test runner for rspec
|
|
89
86
|
test_files: []
|