rspec-multicore-rails 0.2.0.pre1 → 0.2.0.pre2
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 +8 -0
- data/README.md +14 -4
- data/lib/rspec/multicore/rails/database_manager.rb +64 -33
- data/lib/rspec/multicore/rails/version.rb +1 -1
- data/lib/tasks/multicore.rake +39 -20
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cab0db5c29ef823bd0106eae9fe429e50ff913d399735be5eaa3b1ed0ae766f0
|
|
4
|
+
data.tar.gz: a889a51713b6715cdd19f0793025b0c1a74997f20666458760d8a0e33e275d45
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 693239e0fa3955ffad52dea7a694a4ef12d2a63b5ceba3863f5550eed736719cc2c2fe99b4b00564e9c78ef4656e1694feb73ca6207eff7b0a4d9e48bcdfb9dc
|
|
7
|
+
data.tar.gz: 6452f0e220cf4f0911112ecc248910f001a067611cb4ba7aa30ce5983c05891e621be1e406e0eafc6efcbe078e517c05eee523644034cf686dce3e7783610e4f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0.pre2
|
|
4
|
+
|
|
5
|
+
- Uses Rails' standard database tasks to manage worker test databases and
|
|
6
|
+
removes the prerelease custom task namespace.
|
|
7
|
+
- Supports multiple writable test configurations while leaving replicas and
|
|
8
|
+
`database_tasks: false` configurations unmanaged.
|
|
9
|
+
- Improves release validation and retry safety.
|
|
10
|
+
|
|
3
11
|
## 0.2.0.pre1
|
|
4
12
|
|
|
5
13
|
- Uses the core worker count as the single concurrency source.
|
data/README.md
CHANGED
|
@@ -2,14 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
`rspec-multicore-rails` loads `rspec-multicore` and automatically isolates ActiveRecord connections for Rails test workers.
|
|
4
4
|
|
|
5
|
-
Worker 1 uses the base test database. Later workers use `_2`, `_3`, and so on;
|
|
5
|
+
Worker 1 uses the base test database. Later workers use `_2`, `_3`, and so on;
|
|
6
|
+
SQLite suffixes are placed before the extension. The adapter refuses to connect
|
|
7
|
+
workers outside test and clears inherited connections before connecting.
|
|
8
|
+
|
|
9
|
+
Use Rails' standard database tasks to manage the base and worker databases:
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
bin/rails db:prepare
|
|
13
|
+
bin/rails db:test:prepare
|
|
14
|
+
bin/rails db:reset
|
|
11
15
|
```
|
|
12
16
|
|
|
17
|
+
Create, schema-load, prepare, purge, and drop operations extend to the extra
|
|
18
|
+
worker databases whenever the Rails task includes test. Multiple writable test
|
|
19
|
+
configurations are supported; replicas and configurations with
|
|
20
|
+
`database_tasks: false` are not managed. No worker entries are needed in
|
|
21
|
+
`database.yml`, and running RSpec never mutates the database lifecycle.
|
|
22
|
+
|
|
13
23
|
The adapter does not manage Redis, Sidekiq, caches, loggers, SimpleCov, or profilers. Configure those with `RSpec::Multicore.on_worker_fork` and `on_worker_shutdown`.
|
|
14
24
|
|
|
15
25
|
Requires Ruby 3.2+, Rails/ActiveRecord 7.1–8.x, and exactly the matching `rspec-multicore` version.
|
|
@@ -6,71 +6,102 @@ require "active_record/tasks/database_tasks"
|
|
|
6
6
|
module RSpec
|
|
7
7
|
module Multicore
|
|
8
8
|
module Rails
|
|
9
|
-
#
|
|
9
|
+
# Manages and connects worker-owned ActiveRecord test databases.
|
|
10
10
|
class DatabaseManager
|
|
11
|
+
TEST_ENV = "test"
|
|
12
|
+
|
|
11
13
|
def initialize
|
|
12
|
-
|
|
13
|
-
@
|
|
14
|
+
@primary_config = ActiveRecord::Base.connection_db_config
|
|
15
|
+
@configs = test_configs
|
|
16
|
+
@configs << @primary_config unless @configs.include?(@primary_config)
|
|
17
|
+
@base_databases = {}.compare_by_identity
|
|
18
|
+
@configs.each { @base_databases[_1] = _1.database }
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
def connect_worker(slot)
|
|
22
|
+
ensure_test_environment!
|
|
17
23
|
ActiveRecord::Base.connection_handler.clear_all_connections!
|
|
18
|
-
|
|
24
|
+
@configs.each { _1._database = database_for(slot, _1) }
|
|
25
|
+
ActiveRecord::Base.establish_connection(@primary_config)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def create_workers(name: nil) = each_worker_config(name:) { database_tasks.create(_1) }
|
|
29
|
+
|
|
30
|
+
def purge_workers(name: nil)
|
|
31
|
+
each_worker_config(name:) do |config|
|
|
32
|
+
database_tasks.purge(config)
|
|
33
|
+
rescue ActiveRecord::NoDatabaseError
|
|
34
|
+
database_tasks.create(config)
|
|
35
|
+
end
|
|
19
36
|
end
|
|
20
37
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema(hash_config_for(slot))
|
|
38
|
+
def load_schema_workers(name: nil)
|
|
39
|
+
each_worker_config(name:) do |config|
|
|
40
|
+
database_tasks.load_schema(config, schema_format(config))
|
|
25
41
|
end
|
|
26
42
|
end
|
|
27
43
|
|
|
28
|
-
def
|
|
44
|
+
def prepare_workers(name: nil)
|
|
45
|
+
purge_workers(name:)
|
|
46
|
+
load_schema_workers(name:)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def drop_workers(name: nil) = each_worker_config(name:) { database_tasks.drop(_1) }
|
|
29
50
|
|
|
30
51
|
def workers = RSpec::Multicore.workers
|
|
31
|
-
|
|
52
|
+
|
|
53
|
+
def database_for(slot, config = @primary_config)
|
|
54
|
+
return base_database(config) if slot == 1
|
|
55
|
+
|
|
56
|
+
database = base_database(config)
|
|
57
|
+
return "#{database}_#{slot}" unless config.adapter == "sqlite3"
|
|
58
|
+
|
|
59
|
+
extension = File.extname(database)
|
|
60
|
+
"#{database.delete_suffix(extension)}_#{slot}#{extension}"
|
|
61
|
+
end
|
|
32
62
|
|
|
33
63
|
private
|
|
34
64
|
|
|
35
|
-
def
|
|
36
|
-
|
|
65
|
+
def test_configs
|
|
66
|
+
configurations = ActiveRecord::Base.configurations
|
|
67
|
+
Array(configurations.configs_for(env_name: TEST_ENV, include_hidden: true))
|
|
68
|
+
end
|
|
37
69
|
|
|
38
|
-
def
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return "#{base_database.delete_suffix(extension)}_#{slot}#{extension}"
|
|
70
|
+
def task_configs(name: nil)
|
|
71
|
+
@configs.select do |config|
|
|
72
|
+
config.env_name == TEST_ENV && config.database_tasks? && (!name || config.name == name)
|
|
42
73
|
end
|
|
43
|
-
|
|
44
|
-
"#{base_database}_#{slot}"
|
|
45
74
|
end
|
|
46
75
|
|
|
47
|
-
def
|
|
76
|
+
def each_worker_config(name:)
|
|
77
|
+
return enum_for(__method__, name:) unless block_given?
|
|
48
78
|
|
|
49
|
-
|
|
79
|
+
task_configs(name:).each do |config|
|
|
80
|
+
2.upto(workers) { yield derived_config(config, _1) }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
50
83
|
|
|
51
|
-
def
|
|
84
|
+
def derived_config(config, slot)
|
|
52
85
|
ActiveRecord::DatabaseConfigurations::HashConfig.new(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
86
|
+
config.env_name,
|
|
87
|
+
config.name,
|
|
88
|
+
config.configuration_hash.merge(database: database_for(slot, config))
|
|
56
89
|
)
|
|
57
90
|
end
|
|
58
91
|
|
|
59
|
-
def
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
92
|
+
def base_database(config) = @base_databases.fetch(config)
|
|
93
|
+
def database_tasks = ActiveRecord::Tasks::DatabaseTasks
|
|
94
|
+
|
|
95
|
+
def schema_format(config)
|
|
96
|
+
return config.schema_format if config.respond_to?(:schema_format)
|
|
63
97
|
|
|
64
|
-
|
|
65
|
-
ActiveRecord::Tasks::DatabaseTasks.drop(config_for(slot))
|
|
66
|
-
rescue ActiveRecord::NoDatabaseError
|
|
67
|
-
nil
|
|
98
|
+
config.configuration_hash.fetch(:schema_format, ActiveRecord.schema_format)
|
|
68
99
|
end
|
|
69
100
|
|
|
70
101
|
def ensure_test_environment!
|
|
71
102
|
return if ::Rails.env.test?
|
|
72
103
|
|
|
73
|
-
raise RSpec::Multicore::Error, "Parallel databases can only be
|
|
104
|
+
raise RSpec::Multicore::Error, "Parallel databases can only be connected in the Rails test environment"
|
|
74
105
|
end
|
|
75
106
|
end
|
|
76
107
|
end
|
data/lib/tasks/multicore.rake
CHANGED
|
@@ -2,27 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
require "rspec/multicore/rails"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
manager = -> { RSpec::Multicore::Rails::DatabaseManager.new }
|
|
6
|
+
test_in_scope = lambda do
|
|
7
|
+
Rails.env.test? || (Rails.env.development? && !ENV["DATABASE_URL"] && !ENV["SKIP_TEST_DATABASE"])
|
|
8
|
+
end
|
|
9
|
+
allowed = lambda do |scope|
|
|
10
|
+
scope == :all || (scope == :test ? Rails.env.test? : test_in_scope.call)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
enhance = lambda do |task_name, operation, name: nil, scope: :current|
|
|
14
|
+
next unless Rake::Task.task_defined?(task_name)
|
|
15
|
+
|
|
16
|
+
Rake::Task[task_name].enhance do
|
|
17
|
+
next unless allowed.call(scope)
|
|
18
|
+
|
|
19
|
+
manager.call.public_send(operation, name:)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
enhance.call("db:create", :create_workers)
|
|
24
|
+
enhance.call("db:create:all", :create_workers, scope: :all)
|
|
25
|
+
enhance.call("db:prepare", :prepare_workers)
|
|
26
|
+
enhance.call("db:schema:load", :load_schema_workers)
|
|
27
|
+
enhance.call("db:test:purge", :purge_workers, scope: :all)
|
|
28
|
+
enhance.call("db:test:load_schema", :load_schema_workers, scope: :all)
|
|
29
|
+
enhance.call("db:purge", :purge_workers)
|
|
30
|
+
enhance.call("db:purge:all", :purge_workers, scope: :all)
|
|
31
|
+
enhance.call("db:drop", :drop_workers)
|
|
32
|
+
enhance.call("db:drop:all", :drop_workers, scope: :all)
|
|
23
33
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
Rake::Task.tasks.map(&:name).each do |task_name|
|
|
35
|
+
case task_name
|
|
36
|
+
when /\Adb:test:purge:(.+)\z/
|
|
37
|
+
enhance.call(task_name, :purge_workers, name: Regexp.last_match(1), scope: :all)
|
|
38
|
+
when /\Adb:test:load_schema:(.+)\z/
|
|
39
|
+
enhance.call(task_name, :load_schema_workers, name: Regexp.last_match(1), scope: :all)
|
|
40
|
+
when /\Adb:create:(?!all\z)(.+)\z/
|
|
41
|
+
enhance.call(task_name, :create_workers, name: Regexp.last_match(1), scope: :test)
|
|
42
|
+
when /\Adb:schema:load:(.+)\z/
|
|
43
|
+
enhance.call(task_name, :load_schema_workers, name: Regexp.last_match(1), scope: :test)
|
|
44
|
+
when /\Adb:drop:(?!all\z|_unsafe\z)(.+)\z/
|
|
45
|
+
enhance.call(task_name, :drop_workers, name: Regexp.last_match(1), scope: :test)
|
|
27
46
|
end
|
|
28
47
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rspec-multicore-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.0.
|
|
4
|
+
version: 0.2.0.pre2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sveta Markovic
|
|
@@ -55,14 +55,14 @@ dependencies:
|
|
|
55
55
|
requirements:
|
|
56
56
|
- - '='
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: 0.2.0.
|
|
58
|
+
version: 0.2.0.pre2
|
|
59
59
|
type: :runtime
|
|
60
60
|
prerelease: false
|
|
61
61
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
62
|
requirements:
|
|
63
63
|
- - '='
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: 0.2.0.
|
|
65
|
+
version: 0.2.0.pre2
|
|
66
66
|
- !ruby/object:Gem::Dependency
|
|
67
67
|
name: rake
|
|
68
68
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -120,7 +120,7 @@ dependencies:
|
|
|
120
120
|
- !ruby/object:Gem::Version
|
|
121
121
|
version: '2.0'
|
|
122
122
|
description: Rails adapter for rspec-multicore that assigns each worker an isolated
|
|
123
|
-
ActiveRecord test database
|
|
123
|
+
ActiveRecord test database through the standard Rails database-task lifecycle.
|
|
124
124
|
email:
|
|
125
125
|
- svetam.sd@pm.me
|
|
126
126
|
executables: []
|