test_data 0.1.0 → 0.3.0
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/.github/workflows/ruby.yml +1 -5
- data/.standard.yml +2 -0
- data/CHANGELOG.md +38 -1
- data/Gemfile.lock +15 -15
- data/LICENSE.txt +1 -1
- data/README.md +701 -712
- data/example/.gitignore +1 -4
- data/example/Gemfile.lock +1 -1
- data/example/config/application.rb +3 -0
- data/example/config/credentials.yml.enc +1 -2
- data/example/spec/rails_helper.rb +1 -1
- data/example/spec/requests/boops_spec.rb +1 -5
- data/example/spec/requests/rails_fixtures_override_spec.rb +106 -0
- data/example/test/integration/better_mode_switching_demo_test.rb +2 -10
- data/example/test/integration/fixture_load_count_test.rb +82 -0
- data/example/test/integration/load_rollback_truncate_test.rb +40 -45
- data/example/test/integration/mode_switching_demo_test.rb +4 -14
- data/example/test/integration/parallel_boops_with_fixtures_test.rb +1 -5
- data/example/test/integration/parallel_boops_without_fixtures_test.rb +1 -5
- data/example/test/integration/rails_fixtures_double_load_test.rb +2 -2
- data/example/test/integration/rails_fixtures_override_test.rb +18 -35
- data/example/test/integration/test_data_hooks_test.rb +89 -0
- data/example/test/integration/transaction_committing_boops_test.rb +1 -10
- data/example/test/test_helper.rb +1 -5
- data/lib/generators/test_data/environment_file_generator.rb +4 -0
- data/lib/generators/test_data/initializer_generator.rb +19 -13
- data/lib/test_data/config.rb +30 -12
- data/lib/test_data/custom_loaders/abstract_base.rb +25 -0
- data/lib/test_data/custom_loaders/rails_fixtures.rb +45 -0
- data/lib/test_data/detects_database_existence.rb +19 -0
- data/lib/test_data/determines_databases_associated_dump_time.rb +13 -0
- data/lib/test_data/determines_when_sql_dump_was_made.rb +24 -0
- data/lib/test_data/dumps_database.rb +3 -0
- data/lib/test_data/inserts_test_data.rb +25 -0
- data/lib/test_data/manager.rb +187 -0
- data/lib/test_data/railtie.rb +4 -0
- data/lib/test_data/rake.rb +41 -12
- data/lib/test_data/records_dump_metadata.rb +9 -0
- data/lib/test_data/truncates_test_data.rb +31 -0
- data/lib/test_data/version.rb +1 -1
- data/lib/test_data/warns_if_database_is_newer_than_dump.rb +32 -0
- data/lib/test_data/warns_if_dump_is_newer_than_database.rb +36 -0
- data/lib/test_data.rb +43 -1
- data/script/reset_example_app +1 -0
- data/script/test +54 -6
- metadata +17 -3
- data/lib/test_data/transactional_data_loader.rb +0 -300
@@ -1,29 +1,19 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class ModeSwitchingTestCase < ActiveSupport::TestCase
|
4
|
+
self.use_transactional_tests = false
|
5
|
+
|
4
6
|
def self.test_data_mode(mode)
|
5
7
|
if mode == :factory_bot
|
6
8
|
require "factory_bot_rails"
|
7
9
|
include FactoryBot::Syntax::Methods
|
8
10
|
|
9
11
|
setup do
|
10
|
-
TestData.
|
11
|
-
ActiveRecord::Base.connection.begin_transaction(joinable: false, _lazy: false)
|
12
|
-
end
|
13
|
-
|
14
|
-
teardown do
|
15
|
-
ActiveRecord::Base.connection.rollback_transaction
|
12
|
+
TestData.uses_clean_slate
|
16
13
|
end
|
17
|
-
|
18
14
|
elsif mode == :test_data
|
19
|
-
self.use_transactional_tests = false
|
20
|
-
|
21
15
|
setup do
|
22
|
-
TestData.
|
23
|
-
end
|
24
|
-
|
25
|
-
teardown do
|
26
|
-
TestData.rollback
|
16
|
+
TestData.uses_test_data
|
27
17
|
end
|
28
18
|
end
|
29
19
|
end
|
@@ -3,8 +3,8 @@ require "test_helper"
|
|
3
3
|
class FixturesUsingTest < ActiveSupport::TestCase
|
4
4
|
def test_tries_to_load_rails_fixtures_with_test_data
|
5
5
|
error = assert_raises(TestData::Error) do
|
6
|
-
TestData.
|
6
|
+
TestData.uses_rails_fixtures(self)
|
7
7
|
end
|
8
|
-
assert_match "'TestData.
|
8
|
+
assert_match "'TestData.uses_rails_fixtures(self)' depends on Rails' default fixture-loading behavior being disabled by calling 'TestData.prevent_rails_fixtures_from_loading_automatically!' as early as possible (e.g. near the top of your test_helper.rb), but it looks like it was never called", error.message
|
9
9
|
end
|
10
10
|
end
|
@@ -6,26 +6,23 @@ class FixtureFreeTestData < ActiveSupport::TestCase
|
|
6
6
|
fixtures :boops # why not
|
7
7
|
|
8
8
|
setup do
|
9
|
-
TestData.
|
9
|
+
TestData.uses_test_data
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_has_no_fixture_boops
|
13
13
|
assert_equal 15, Boop.count
|
14
14
|
end
|
15
|
-
|
16
|
-
teardown do
|
17
|
-
TestData.rollback
|
18
|
-
end
|
19
15
|
end
|
20
16
|
|
21
17
|
class FixturesUsingTest < ActiveSupport::TestCase
|
22
18
|
fixtures :boops
|
23
19
|
|
24
20
|
setup do
|
25
|
-
TestData.
|
21
|
+
TestData.uses_rails_fixtures(self)
|
26
22
|
end
|
27
23
|
|
28
24
|
def test_has_fixture_boops
|
25
|
+
assert boops(:boop_1).persisted?
|
29
26
|
assert_equal 2, Boop.count
|
30
27
|
end
|
31
28
|
|
@@ -34,29 +31,25 @@ class FixturesUsingTest < ActiveSupport::TestCase
|
|
34
31
|
end
|
35
32
|
|
36
33
|
def test_even_explicitly_loading_test_data_will_truncate_and_then_load_fixtures
|
37
|
-
TestData.
|
38
|
-
TestData.
|
34
|
+
TestData.uses_test_data
|
35
|
+
TestData.uses_rails_fixtures(self)
|
39
36
|
|
40
37
|
assert_equal 2, Boop.count
|
41
38
|
end
|
42
39
|
|
43
40
|
def test_load_and_rollback_leaves_them_as_is
|
44
41
|
boop = Boop.first
|
45
|
-
|
46
|
-
a_year_ago = 1.year.ago
|
42
|
+
original_created_on = boop.created_at.to_date
|
43
|
+
a_year_ago = 1.year.ago.to_date
|
47
44
|
|
48
45
|
boop.update!(created_at: a_year_ago)
|
49
46
|
|
50
|
-
assert_equal Boop.find(boop.id).created_at, a_year_ago
|
47
|
+
assert_equal Boop.find(boop.id).created_at.to_date, a_year_ago
|
51
48
|
|
52
|
-
# Now
|
53
|
-
TestData.
|
49
|
+
# Now trigger a rollback to the fixtures point
|
50
|
+
TestData.uses_rails_fixtures(self)
|
54
51
|
|
55
|
-
assert_equal Boop.find(boop.id).created_at,
|
56
|
-
end
|
57
|
-
|
58
|
-
teardown do
|
59
|
-
TestData.rollback(:after_load_rails_fixtures)
|
52
|
+
assert_equal Boop.find(boop.id).created_at.to_date, original_created_on
|
60
53
|
end
|
61
54
|
end
|
62
55
|
|
@@ -65,35 +58,29 @@ class SomeFixturesAndSomeTestDataInOneClassTest < ActiveSupport::TestCase
|
|
65
58
|
fixtures :all
|
66
59
|
|
67
60
|
def test_fixtures_work
|
68
|
-
TestData.
|
61
|
+
TestData.uses_rails_fixtures(self)
|
69
62
|
|
70
63
|
assert_equal Date.civil(2020, 1, 1), boops(:boop_1).updated_at.to_date
|
71
64
|
assert_equal "Levi", pants(:pant_1).brand
|
72
|
-
|
73
|
-
TestData.rollback(:after_load_rails_fixtures)
|
74
65
|
end
|
75
66
|
|
76
67
|
def test_that_rewinds_to_test_data
|
77
|
-
TestData.
|
68
|
+
TestData.uses_test_data
|
78
69
|
|
79
70
|
assert_equal 15, Boop.count
|
80
|
-
|
81
|
-
TestData.rollback
|
82
71
|
end
|
83
72
|
|
84
73
|
def test_that_rewinds_to_the_very_start
|
85
|
-
TestData.
|
74
|
+
TestData.uninitialize
|
86
75
|
|
87
76
|
assert_equal 0, Boop.count
|
88
77
|
end
|
89
78
|
|
90
79
|
def test_fixtures_get_reloaded_because_cache_is_cleared
|
91
|
-
TestData.
|
80
|
+
TestData.uses_rails_fixtures(self)
|
92
81
|
|
93
82
|
assert_equal Date.civil(2019, 1, 1), boops(:boop_2).updated_at.to_date
|
94
83
|
assert_equal "Wrangler", pants(:pant_2).brand
|
95
|
-
|
96
|
-
TestData.rollback(:after_load_rails_fixtures)
|
97
84
|
end
|
98
85
|
end
|
99
86
|
|
@@ -101,11 +88,7 @@ class PantsFixturesTest < ActiveSupport::TestCase
|
|
101
88
|
fixtures :pants
|
102
89
|
|
103
90
|
setup do
|
104
|
-
TestData.
|
105
|
-
end
|
106
|
-
|
107
|
-
teardown do
|
108
|
-
TestData.rollback(:after_load_rails_fixtures)
|
91
|
+
TestData.uses_rails_fixtures(self)
|
109
92
|
end
|
110
93
|
|
111
94
|
def test_has_fixture_pants
|
@@ -120,8 +103,8 @@ end
|
|
120
103
|
class FixtureTestPassingTheWrongThingTest < ActiveSupport::TestCase
|
121
104
|
def test_doing_it_wrong
|
122
105
|
error = assert_raises(TestData::Error) do
|
123
|
-
TestData.
|
106
|
+
TestData.uses_rails_fixtures(ActiveRecord::Base)
|
124
107
|
end
|
125
|
-
assert_match "'TestData.
|
108
|
+
assert_match "'TestData.uses_rails_fixtures(self)' must be passed a test instance that has had ActiveRecord::TestFixtures mixed-in (e.g. `TestData.uses_rails_fixtures(self)` in an ActiveSupport::TestCase `setup` block), but the provided argument does not respond to 'setup_fixtures'", error.message
|
126
109
|
end
|
127
110
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
TestData.config do |config|
|
4
|
+
config.after_test_data_load { MetaBoop.refresh_materialized_view }
|
5
|
+
config.after_test_data_truncate(-> { MetaBoop.refresh_materialized_view })
|
6
|
+
config.after_rails_fixture_load { MetaBoop.refresh_materialized_view }
|
7
|
+
end
|
8
|
+
|
9
|
+
TestData.prevent_rails_fixtures_from_loading_automatically!
|
10
|
+
MetaBoop.refresh_materialized_view # count = 1
|
11
|
+
|
12
|
+
class TestDataHooksTest < ActiveSupport::TestCase
|
13
|
+
fixtures :all
|
14
|
+
i_suck_and_my_tests_are_order_dependent!
|
15
|
+
|
16
|
+
def test_uses_test_data_hook
|
17
|
+
assert_equal 1, MetaBoop.refresh_materialized_view_count
|
18
|
+
MetaBoop.reset_refresh_materialized_view_count
|
19
|
+
|
20
|
+
# Materialized view is refreshed and called 1 time
|
21
|
+
TestData.uses_test_data
|
22
|
+
assert_equal 15, Boop.count
|
23
|
+
assert_equal 15, MetaBoop.count
|
24
|
+
assert_equal 1, MetaBoop.refresh_materialized_view_count
|
25
|
+
MetaBoop.reset_refresh_materialized_view_count
|
26
|
+
|
27
|
+
# Rollbacks also rollback to materialized view changes without calling again
|
28
|
+
Boop.create!(other_boop: Boop.new)
|
29
|
+
assert_equal 16, Boop.count
|
30
|
+
assert_equal 15, MetaBoop.count
|
31
|
+
MetaBoop.refresh_materialized_view
|
32
|
+
assert_equal 16, MetaBoop.count
|
33
|
+
assert_equal 1, MetaBoop.refresh_materialized_view_count
|
34
|
+
TestData.uses_test_data
|
35
|
+
assert_equal 15, Boop.count
|
36
|
+
assert_equal 15, MetaBoop.count
|
37
|
+
assert_equal 1, MetaBoop.refresh_materialized_view_count
|
38
|
+
MetaBoop.reset_refresh_materialized_view_count
|
39
|
+
|
40
|
+
# The same hook also works when cleaning slates
|
41
|
+
TestData.uses_clean_slate
|
42
|
+
assert_equal 0, Boop.count
|
43
|
+
assert_equal 0, MetaBoop.count
|
44
|
+
assert_equal 1, MetaBoop.refresh_materialized_view_count
|
45
|
+
Boop.create!(other_boop: Boop.new)
|
46
|
+
MetaBoop.refresh_materialized_view
|
47
|
+
assert_equal 1, Boop.count
|
48
|
+
assert_equal 1, MetaBoop.count
|
49
|
+
assert_equal 2, MetaBoop.refresh_materialized_view_count
|
50
|
+
TestData.uses_clean_slate
|
51
|
+
assert_equal 0, Boop.count
|
52
|
+
assert_equal 0, MetaBoop.count
|
53
|
+
assert_equal 2, MetaBoop.refresh_materialized_view_count
|
54
|
+
MetaBoop.reset_refresh_materialized_view_count
|
55
|
+
|
56
|
+
# The same hook works with fixtures
|
57
|
+
TestData.uses_rails_fixtures(self)
|
58
|
+
assert_equal 2, Boop.count
|
59
|
+
assert_equal 2, MetaBoop.count
|
60
|
+
assert_equal 1, MetaBoop.refresh_materialized_view_count
|
61
|
+
Boop.first.delete
|
62
|
+
assert_equal 1, Boop.count
|
63
|
+
assert_equal 2, MetaBoop.count
|
64
|
+
MetaBoop.refresh_materialized_view
|
65
|
+
assert_equal 1, MetaBoop.count
|
66
|
+
assert_equal 2, MetaBoop.refresh_materialized_view_count
|
67
|
+
TestData.uses_rails_fixtures(self)
|
68
|
+
assert_equal 2, Boop.count
|
69
|
+
assert_equal 2, MetaBoop.count
|
70
|
+
assert_equal 2, MetaBoop.refresh_materialized_view_count
|
71
|
+
MetaBoop.reset_refresh_materialized_view_count
|
72
|
+
|
73
|
+
# Rewinding two steps will not call refresh materialized views
|
74
|
+
TestData.uses_test_data
|
75
|
+
assert_equal 15, Boop.count
|
76
|
+
assert_equal 15, MetaBoop.count
|
77
|
+
assert_equal 0, MetaBoop.refresh_materialized_view_count
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_that_hooks_require_valid_settings
|
81
|
+
foo = Struct.new(:thing)
|
82
|
+
assert_raises(TestData::Error) { TestData.config.after_test_data_load(nil) }
|
83
|
+
assert_raises(TestData::Error) { TestData.config.after_test_data_truncate(nil) }
|
84
|
+
assert_raises(TestData::Error) { TestData.config.after_rails_fixture_load(nil) }
|
85
|
+
assert_raises(TestData::Error) { TestData.config.after_test_data_load(foo) }
|
86
|
+
assert_raises(TestData::Error) { TestData.config.after_test_data_truncate(foo) }
|
87
|
+
assert_raises(TestData::Error) { TestData.config.after_rails_fixture_load(foo) }
|
88
|
+
end
|
89
|
+
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
TestData.config.use_transactional_data_loader = false
|
4
|
-
|
5
3
|
class TransactionCommittingTestCase < ActiveSupport::TestCase
|
6
4
|
self.use_transactional_tests = false
|
7
5
|
|
8
6
|
setup do
|
9
7
|
Noncommittal.stop!
|
10
|
-
TestData.
|
8
|
+
TestData.insert_test_data_dump
|
11
9
|
end
|
12
10
|
|
13
11
|
teardown do
|
@@ -26,11 +24,4 @@ class TransactionCommittingBoopsTest < TransactionCommittingTestCase
|
|
26
24
|
def test_finds_the_boops_via_another_process
|
27
25
|
assert_equal 15, `RAILS_ENV=test bin/rails runner "puts Boop.count"`.chomp.to_i
|
28
26
|
end
|
29
|
-
|
30
|
-
def test_cant_have_it_both_ways
|
31
|
-
error = assert_raise(TestData::Error) do
|
32
|
-
TestData.config.use_transactional_data_loader = true
|
33
|
-
end
|
34
|
-
assert_match "There is already a non-transactional data loader", error.message
|
35
|
-
end
|
36
27
|
end
|
data/example/test/test_helper.rb
CHANGED
@@ -9,6 +9,10 @@ module TestData
|
|
9
9
|
require_relative "development"
|
10
10
|
|
11
11
|
Rails.application.configure do
|
12
|
+
# Rails creates secret key base for only "development" and "test"
|
13
|
+
# For more info, see: https://github.com/testdouble/test_data/issues/2
|
14
|
+
self.secrets.secret_key_base ||= Rails.application.send(:generate_development_secret)
|
15
|
+
|
12
16
|
# Don't persist schema.rb or structure.sql after test_data is migrated
|
13
17
|
config.active_record.dump_schema_after_migration = false
|
14
18
|
end
|
@@ -8,14 +8,17 @@ module TestData
|
|
8
8
|
return unless defined?(TestData)
|
9
9
|
|
10
10
|
TestData.config do |config|
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# Hook run after test data is loaded by `TestData.uses_test_data`,
|
12
|
+
# but before a savepoint is taken
|
13
|
+
# config.after_test_data_load { }
|
13
14
|
|
14
|
-
#
|
15
|
-
#
|
15
|
+
# Hook run after test data is truncated by `TestData.uses_clean_slate`,
|
16
|
+
# but before a savepoint is taken
|
17
|
+
# config.after_test_data_truncate { }
|
16
18
|
|
17
|
-
#
|
18
|
-
#
|
19
|
+
# Hook run after test data is truncated by `TestData.uses_rails_fixtures`,
|
20
|
+
# but before a savepoint is taken
|
21
|
+
# config.after_rails_fixture_load { }
|
19
22
|
|
20
23
|
# Tables whose data shouldn't be loaded into tests.
|
21
24
|
# ("ar_internal_metadata" and "schema_migrations" are always excluded)
|
@@ -24,17 +27,20 @@ module TestData
|
|
24
27
|
# Tables whose data should be excluded from SQL dumps (still dumps their schema DDL)
|
25
28
|
# config.dont_dump_these_tables = []
|
26
29
|
|
27
|
-
#
|
30
|
+
# Where to store SQL dumps of the test_data database schema
|
31
|
+
# config.schema_dump_path = "test/support/test_data/schema.sql"
|
32
|
+
|
33
|
+
# Where to store SQL dumps of the test_data database test data
|
34
|
+
# config.data_dump_path = "test/support/test_data/data.sql"
|
35
|
+
|
36
|
+
# Where to store SQL dumps of the test_data database non-test data
|
37
|
+
# config.non_test_data_dump_path = "test/support/test_data/non_test_data.sql"
|
38
|
+
|
39
|
+
# Tables whose data should be truncated by TestData.uses_clean_slate
|
28
40
|
# If left as `nil`, all tables inserted into by the SQL file at
|
29
41
|
# `data_dump_path` will be truncated
|
30
42
|
# config.truncate_these_test_data_tables = nil
|
31
43
|
|
32
|
-
# Perform TestData.load and TestData.truncate inside nested
|
33
|
-
# transactions for increased test isolation and speed. Setting this
|
34
|
-
# to false will disable several features that depend on transactions
|
35
|
-
# being used
|
36
|
-
# config.use_transactional_data_loader = true
|
37
|
-
|
38
44
|
# Log level (valid values: [:debug, :info, :warn, :error, :quiet])
|
39
45
|
# Can also be set with env var TEST_DATA_LOG_LEVEL
|
40
46
|
# config.log_level = :info
|
data/lib/test_data/config.rb
CHANGED
@@ -29,18 +29,9 @@ module TestData
|
|
29
29
|
# Tables to exclude from all dumps
|
30
30
|
attr_accessor :dont_dump_these_tables
|
31
31
|
|
32
|
-
# Tables to truncate when TestData.
|
32
|
+
# Tables to truncate when TestData.uses_clean_slate is called
|
33
33
|
attr_accessor :truncate_these_test_data_tables
|
34
34
|
|
35
|
-
# Perform TestData.load and TestData.truncate inside nested
|
36
|
-
# transactions for increased test isolation and speed. Setting this to false
|
37
|
-
# will disable several features that depend on transactions being used
|
38
|
-
attr_reader :use_transactional_data_loader
|
39
|
-
def use_transactional_data_loader=(use_transactions)
|
40
|
-
TestData.ensure_we_dont_mix_transactional_and_non_transactional_data_loaders!(use_transactions)
|
41
|
-
@use_transactional_data_loader = use_transactions
|
42
|
-
end
|
43
|
-
|
44
35
|
# Log level (valid values: [:debug, :info, :warn, :error, :quiet])
|
45
36
|
def log_level
|
46
37
|
TestData.log.level
|
@@ -50,7 +41,8 @@ module TestData
|
|
50
41
|
TestData.log.level = level
|
51
42
|
end
|
52
43
|
|
53
|
-
attr_reader :pwd, :cable_yaml_path, :database_yaml_path, :secrets_yaml_path
|
44
|
+
attr_reader :pwd, :cable_yaml_path, :database_yaml_path, :secrets_yaml_path,
|
45
|
+
:after_test_data_load_hook, :after_test_data_truncate_hook, :after_rails_fixture_load_hook
|
54
46
|
|
55
47
|
def self.full_path_reader(*relative_path_readers)
|
56
48
|
relative_path_readers.each do |relative_path_reader|
|
@@ -73,7 +65,33 @@ module TestData
|
|
73
65
|
@non_test_data_tables = []
|
74
66
|
@dont_dump_these_tables = []
|
75
67
|
@truncate_these_test_data_tables = nil
|
76
|
-
@
|
68
|
+
@after_test_data_load_hook = -> {}
|
69
|
+
@after_test_data_truncate_hook = -> {}
|
70
|
+
@after_rails_fixture_load_hook = -> {}
|
71
|
+
end
|
72
|
+
|
73
|
+
def after_test_data_load(callable = nil, &blk)
|
74
|
+
hook = callable || blk
|
75
|
+
if !hook.respond_to?(:call)
|
76
|
+
raise Error.new("after_test_data_load must be passed a callable (e.g. a Proc) or called with a block")
|
77
|
+
end
|
78
|
+
@after_test_data_load_hook = hook
|
79
|
+
end
|
80
|
+
|
81
|
+
def after_test_data_truncate(callable = nil, &blk)
|
82
|
+
hook = callable || blk
|
83
|
+
if !hook.respond_to?(:call)
|
84
|
+
raise Error.new("after_test_data_truncate must be passed a callable (e.g. a Proc) or called with a block")
|
85
|
+
end
|
86
|
+
@after_test_data_truncate_hook = hook
|
87
|
+
end
|
88
|
+
|
89
|
+
def after_rails_fixture_load(callable = nil, &blk)
|
90
|
+
hook = callable || blk
|
91
|
+
if !hook.respond_to?(:call)
|
92
|
+
raise Error.new("after_rails_fixture_load must be passed a callable (e.g. a Proc) or called with a block")
|
93
|
+
end
|
94
|
+
@after_rails_fixture_load_hook = hook
|
77
95
|
end
|
78
96
|
|
79
97
|
def database_yaml
|