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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '082ad795d53684a33439d9c56e8d4ff175460d6b335bf25dfbc0114f913a764e'
4
- data.tar.gz: ddedba7528e3cd7eaa045b55814c1a4d85a09bb69d9dcceb57c843d00244cec8
3
+ metadata.gz: 880d64a3a408ec26218ffc3d108ef6aa12b14da3a6f8d6b5e6ad5d8599373e0b
4
+ data.tar.gz: 421c5c55606788739b895d559d6093032454a831f47a18e5d5a616b76d0ccf49
5
5
  SHA512:
6
- metadata.gz: 9620094891ec8e360d4427f001711ea4b9e2393020f83706ba86840e135d636d04cb13f2442e97b71a8cbc4bbe12b75354ae86c7e3899fa06035a553b2a29377
7
- data.tar.gz: 6842b752e4d66f10b5fed3070aa7fcb7edc7470c3b873fc5da9c8ec86f113e36d1743b0d4193c2966c80acb6638c4cb1b3626b1a2060e813334c2c62392b8d14
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
- In order to bootstrap the test environment, there is a rake task:
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/)
@@ -6,9 +6,9 @@ module RSpec
6
6
  module Conductor
7
7
  class CLI
8
8
  DEFAULTS = {
9
- workers: 4,
9
+ workers: Conductor.default_worker_count,
10
10
  offset: 0,
11
- first_is_1: false,
11
+ first_is_1: Conductor.default_first_is_1?,
12
12
  seed: nil,
13
13
  fail_fast_after: nil,
14
14
  verbose: false,
@@ -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
- @first_is_one = opts.fetch(:first_is_1, false)
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 @first_is_one || worker_number != 1
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(tty = $stdout)
126
- return 80 unless tty.tty?
125
+ def tty_width(io = $stdout)
126
+ return 80 unless io.tty?
127
127
 
128
- tty.winsize[1]
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(tty = $stdout)
132
- return 50 unless tty.tty?
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
- tty.winsize[0]
140
+ height
135
141
  end
136
142
  end
137
143
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Conductor
5
- VERSION = "1.0.3"
5
+ VERSION = "1.0.4"
6
6
  end
7
7
  end
@@ -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
- ENV["RSPEC_CONDUCTOR_FIRST_IS_1"] == "1"
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::DatabaseTasks.default_worker_count})"
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::DatabaseTasks.default_worker_count).to_i
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::DatabaseTasks.default_worker_count})"
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::DatabaseTasks.default_worker_count).to_i
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::DatabaseTasks.default_worker_count})"
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::DatabaseTasks.default_worker_count).to_i
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", *Rake.application.top_level_tasks)
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.3
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: 2026-02-08 00:00:00.000000000 Z
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: 3.3.26
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: []