test_data 0.0.1 → 0.2.1

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +41 -0
  3. data/.standard.yml +2 -0
  4. data/CHANGELOG.md +43 -0
  5. data/Gemfile.lock +17 -15
  6. data/LICENSE.txt +1 -6
  7. data/README.md +1232 -17
  8. data/example/.gitignore +1 -4
  9. data/example/Gemfile +3 -0
  10. data/example/Gemfile.lock +100 -71
  11. data/example/README.md +2 -22
  12. data/example/config/application.rb +3 -0
  13. data/example/config/credentials.yml.enc +1 -1
  14. data/example/config/database.yml +2 -0
  15. data/example/spec/rails_helper.rb +64 -0
  16. data/example/spec/requests/boops_spec.rb +17 -0
  17. data/example/spec/requests/rails_fixtures_override_spec.rb +106 -0
  18. data/example/spec/spec_helper.rb +94 -0
  19. data/example/test/factories.rb +4 -0
  20. data/example/test/integration/better_mode_switching_demo_test.rb +41 -0
  21. data/example/test/integration/boops_that_boop_boops_test.rb +17 -0
  22. data/example/test/integration/dont_dump_tables_test.rb +7 -0
  23. data/example/test/integration/load_rollback_truncate_test.rb +190 -0
  24. data/example/test/integration/mode_switching_demo_test.rb +38 -0
  25. data/example/test/integration/parallel_boops_with_fixtures_test.rb +10 -0
  26. data/example/test/integration/parallel_boops_without_fixtures_test.rb +9 -0
  27. data/example/test/integration/rails_fixtures_double_load_test.rb +10 -0
  28. data/example/test/integration/rails_fixtures_override_test.rb +110 -0
  29. data/example/test/integration/test_data_hooks_test.rb +89 -0
  30. data/example/test/integration/transaction_committing_boops_test.rb +27 -0
  31. data/example/test/test_helper.rb +4 -31
  32. data/lib/generators/test_data/cable_yaml_generator.rb +18 -0
  33. data/lib/generators/test_data/database_yaml_generator.rb +3 -4
  34. data/lib/generators/test_data/environment_file_generator.rb +7 -14
  35. data/lib/generators/test_data/initializer_generator.rb +51 -0
  36. data/lib/generators/test_data/secrets_yaml_generator.rb +19 -0
  37. data/lib/generators/test_data/webpacker_yaml_generator.rb +4 -3
  38. data/lib/test_data.rb +42 -1
  39. data/lib/test_data/active_record_ext.rb +11 -0
  40. data/lib/test_data/config.rb +57 -4
  41. data/lib/test_data/configurators.rb +3 -0
  42. data/lib/test_data/configurators/cable_yaml.rb +25 -0
  43. data/lib/test_data/configurators/environment_file.rb +3 -2
  44. data/lib/test_data/configurators/initializer.rb +26 -0
  45. data/lib/test_data/configurators/secrets_yaml.rb +25 -0
  46. data/lib/test_data/configurators/webpacker_yaml.rb +4 -3
  47. data/lib/test_data/custom_loaders/abstract_base.rb +25 -0
  48. data/lib/test_data/custom_loaders/rails_fixtures.rb +42 -0
  49. data/lib/test_data/dumps_database.rb +55 -5
  50. data/lib/test_data/generator_support.rb +3 -0
  51. data/lib/test_data/inserts_test_data.rb +25 -0
  52. data/lib/test_data/loads_database_dumps.rb +8 -8
  53. data/lib/test_data/log.rb +76 -0
  54. data/lib/test_data/manager.rb +187 -0
  55. data/lib/test_data/rake.rb +20 -9
  56. data/lib/test_data/save_point.rb +34 -0
  57. data/lib/test_data/statistics.rb +31 -0
  58. data/lib/test_data/truncates_test_data.rb +31 -0
  59. data/lib/test_data/verifies_dumps_are_loadable.rb +4 -4
  60. data/lib/test_data/version.rb +1 -1
  61. data/script/reset_example_app +18 -0
  62. data/script/test +78 -13
  63. data/test_data.gemspec +1 -1
  64. metadata +36 -4
  65. data/lib/test_data/transactional_data_loader.rb +0 -77
@@ -0,0 +1,110 @@
1
+ require "test_helper"
2
+
3
+ TestData.prevent_rails_fixtures_from_loading_automatically!
4
+
5
+ class FixtureFreeTestData < ActiveSupport::TestCase
6
+ fixtures :boops # why not
7
+
8
+ setup do
9
+ TestData.uses_test_data
10
+ end
11
+
12
+ def test_has_no_fixture_boops
13
+ assert_equal 15, Boop.count
14
+ end
15
+ end
16
+
17
+ class FixturesUsingTest < ActiveSupport::TestCase
18
+ fixtures :boops
19
+
20
+ setup do
21
+ TestData.uses_rails_fixtures(self)
22
+ end
23
+
24
+ def test_has_fixture_boops
25
+ assert boops(:boop_1).persisted?
26
+ assert_equal 2, Boop.count
27
+ end
28
+
29
+ def test_does_not_get_the_other_fixture_accessor
30
+ assert_raises(NameError) { method(:pants) }
31
+ end
32
+
33
+ def test_even_explicitly_loading_test_data_will_truncate_and_then_load_fixtures
34
+ TestData.uses_test_data
35
+ TestData.uses_rails_fixtures(self)
36
+
37
+ assert_equal 2, Boop.count
38
+ end
39
+
40
+ def test_load_and_rollback_leaves_them_as_is
41
+ boop = Boop.first
42
+ original_created_on = boop.created_at.to_date
43
+ a_year_ago = 1.year.ago.to_date
44
+
45
+ boop.update!(created_at: a_year_ago)
46
+
47
+ assert_equal Boop.find(boop.id).created_at.to_date, a_year_ago
48
+
49
+ # Now trigger a rollback to the fixtures point
50
+ TestData.uses_rails_fixtures(self)
51
+
52
+ assert_equal Boop.find(boop.id).created_at.to_date, original_created_on
53
+ end
54
+ end
55
+
56
+ class SomeFixturesAndSomeTestDataInOneClassTest < ActiveSupport::TestCase
57
+ i_suck_and_my_tests_are_order_dependent!
58
+ fixtures :all
59
+
60
+ def test_fixtures_work
61
+ TestData.uses_rails_fixtures(self)
62
+
63
+ assert_equal Date.civil(2020, 1, 1), boops(:boop_1).updated_at.to_date
64
+ assert_equal "Levi", pants(:pant_1).brand
65
+ end
66
+
67
+ def test_that_rewinds_to_test_data
68
+ TestData.uses_test_data
69
+
70
+ assert_equal 15, Boop.count
71
+ end
72
+
73
+ def test_that_rewinds_to_the_very_start
74
+ TestData.uninitialize
75
+
76
+ assert_equal 0, Boop.count
77
+ end
78
+
79
+ def test_fixtures_get_reloaded_because_cache_is_cleared
80
+ TestData.uses_rails_fixtures(self)
81
+
82
+ assert_equal Date.civil(2019, 1, 1), boops(:boop_2).updated_at.to_date
83
+ assert_equal "Wrangler", pants(:pant_2).brand
84
+ end
85
+ end
86
+
87
+ class PantsFixturesTest < ActiveSupport::TestCase
88
+ fixtures :pants
89
+
90
+ setup do
91
+ TestData.uses_rails_fixtures(self)
92
+ end
93
+
94
+ def test_has_fixture_pants
95
+ assert_equal 2, Pant.count
96
+ end
97
+
98
+ def test_does_not_get_the_other_fixture_accessor
99
+ assert_raises(NameError) { method(:boops) }
100
+ end
101
+ end
102
+
103
+ class FixtureTestPassingTheWrongThingTest < ActiveSupport::TestCase
104
+ def test_doing_it_wrong
105
+ error = assert_raises(TestData::Error) do
106
+ TestData.uses_rails_fixtures(ActiveRecord::Base)
107
+ end
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
109
+ end
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
@@ -0,0 +1,27 @@
1
+ require "test_helper"
2
+
3
+ class TransactionCommittingTestCase < ActiveSupport::TestCase
4
+ self.use_transactional_tests = false
5
+
6
+ setup do
7
+ Noncommittal.stop!
8
+ TestData.insert_test_data_dump
9
+ end
10
+
11
+ teardown do
12
+ Boop.delete_all
13
+ Noncommittal.start!
14
+ end
15
+ end
16
+
17
+ class TransactionCommittingBoopsTest < TransactionCommittingTestCase
18
+ i_suck_and_my_tests_are_order_dependent!
19
+
20
+ def test_finds_the_boops
21
+ assert_equal 15, Boop.count
22
+ end
23
+
24
+ def test_finds_the_boops_via_another_process
25
+ assert_equal 15, `RAILS_ENV=test bin/rails runner "puts Boop.count"`.chomp.to_i
26
+ end
27
+ end
@@ -2,40 +2,13 @@ ENV["RAILS_ENV"] ||= "test"
2
2
  require_relative "../config/environment"
3
3
  require "rails/test_help"
4
4
 
5
+ Noncommittal.start!
6
+
5
7
  class SerializedNonTransactionalTestCase < ActiveSupport::TestCase
6
8
  parallelize(workers: 1)
7
9
  self.use_transactional_tests = false
8
10
 
9
- def setup
10
- TestData.load_data_dump
11
- end
12
-
13
- def teardown
14
- TestData.rollback
15
- end
16
- end
17
-
18
- class ParallelizedTransactionalFixturefullTestCase < ActiveSupport::TestCase
19
- parallelize(workers: :number_of_processors)
20
- self.use_transactional_tests = true
21
- fixtures :all
22
-
23
- def setup
24
- TestData.load_data_dump
25
- end
26
-
27
- # use_transactional_tests will cause a single rollback on teardown
28
- end
29
-
30
- class ParallelizedNonTransactionalFixturelessTestCase < ActiveSupport::TestCase
31
- parallelize(workers: :number_of_processors)
32
- self.use_transactional_tests = false
33
-
34
- def setup
35
- TestData.load_data_dump
36
- end
37
-
38
- def teardown
39
- TestData.rollback
11
+ setup do
12
+ TestData.uses_test_data
40
13
  end
41
14
  end
@@ -0,0 +1,18 @@
1
+ require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
3
+
4
+ module TestData
5
+ class CableYamlGenerator < Rails::Generators::Base
6
+ def call
7
+ unless Configurators::CableYaml.new.verify.looks_good?
8
+ inject_into_file "config/cable.yml", before: BEFORE_TEST_STANZA_REGEX do
9
+ <<~YAML
10
+
11
+ test_data:
12
+ adapter: async
13
+ YAML
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,15 +1,14 @@
1
1
  require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
2
3
 
3
4
  module TestData
4
5
  class DatabaseYamlGenerator < Rails::Generators::Base
5
- BEFORE_TEST_DATABASE_STANZA_REGEX = /^$\n(?:^\#.*\n)*^test:/
6
-
7
6
  def call
8
7
  if Configurators::DatabaseYaml.new.verify.looks_good?
9
- warn "'test_data' section already defined in config/database.yml"
8
+ TestData.log.info "'test_data' section already defined in config/database.yml"
10
9
  else
11
10
  app_name = Rails.application.railtie_name.chomp("_application")
12
- inject_into_file "config/database.yml", before: BEFORE_TEST_DATABASE_STANZA_REGEX do
11
+ inject_into_file "config/database.yml", before: BEFORE_TEST_STANZA_REGEX do
13
12
  <<~YAML
14
13
 
15
14
  # Used in conjunction with the test_data gem
@@ -1,26 +1,19 @@
1
1
  require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
2
3
 
3
4
  module TestData
4
5
  class EnvironmentFileGenerator < Rails::Generators::Base
5
6
  def call
6
7
  create_file "config/environments/test_data.rb", <<~RUBY
8
+ # Load the development environment as a starting point
7
9
  require_relative "development"
8
10
 
9
- TestData.config do |config|
10
- # Where to store SQL dumps of the test_data database schema
11
- # config.schema_dump_path = "test/support/test_data/schema.sql"
12
-
13
- # Where to store SQL dumps of the test_data database test data
14
- # config.data_dump_path = "test/support/test_data/data.sql"
15
-
16
- # Where to store SQL dumps of the test_data database non-test data
17
- # config.non_test_data_dump_path = "test/support/test_data/non_test_data.sql"
18
-
19
- # Tables whose data shouldn't be loaded into tests
20
- # config.non_test_data_tables = ["ar_internal_metadata", "schema_migrations"]
21
- end
22
-
23
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
+
16
+ # Don't persist schema.rb or structure.sql after test_data is migrated
24
17
  config.active_record.dump_schema_after_migration = false
25
18
  end
26
19
  RUBY
@@ -0,0 +1,51 @@
1
+ require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
3
+
4
+ module TestData
5
+ class InitializerGenerator < Rails::Generators::Base
6
+ def call
7
+ create_file "config/initializers/test_data.rb", <<~RUBY
8
+ return unless defined?(TestData)
9
+
10
+ TestData.config do |config|
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 { }
14
+
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 { }
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 { }
22
+
23
+ # Tables whose data shouldn't be loaded into tests.
24
+ # ("ar_internal_metadata" and "schema_migrations" are always excluded)
25
+ # config.non_test_data_tables = []
26
+
27
+ # Tables whose data should be excluded from SQL dumps (still dumps their schema DDL)
28
+ # config.dont_dump_these_tables = []
29
+
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
40
+ # If left as `nil`, all tables inserted into by the SQL file at
41
+ # `data_dump_path` will be truncated
42
+ # config.truncate_these_test_data_tables = nil
43
+
44
+ # Log level (valid values: [:debug, :info, :warn, :error, :quiet])
45
+ # Can also be set with env var TEST_DATA_LOG_LEVEL
46
+ # config.log_level = :info
47
+ end
48
+ RUBY
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
3
+
4
+ module TestData
5
+ class SecretsYamlGenerator < Rails::Generators::Base
6
+ def call
7
+ unless Configurators::SecretsYaml.new.verify.looks_good?
8
+ inject_into_file "config/secrets.yml", before: BEFORE_TEST_STANZA_REGEX do
9
+ <<~YAML
10
+
11
+ # Simplify configuration with the test_data environment
12
+ test_data:
13
+ secret_key_base: #{SecureRandom.hex(64)}
14
+ YAML
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,23 +1,24 @@
1
1
  require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
2
3
 
3
4
  module TestData
4
5
  class WebpackerYamlGenerator < Rails::Generators::Base
5
6
  AFTER_DEVELOPMENT_WEBPACK_STANZA_REGEX = /^development:/
6
- BEFORE_TEST_WEBPACK_STANZA_REGEX = /^$\n(?:^\#.*\n)*^test:/
7
7
 
8
8
  def call
9
9
  if Configurators::WebpackerYaml.new.verify.looks_good?
10
- warn "'test_data' section not needed in config/webpacker.yml"
10
+ TestData.log.debug "'test_data' section not needed in config/webpacker.yml"
11
11
  else
12
12
  inject_into_file "config/webpacker.yml", after: AFTER_DEVELOPMENT_WEBPACK_STANZA_REGEX do
13
13
  " &development"
14
14
  end
15
- inject_into_file "config/webpacker.yml", before: BEFORE_TEST_WEBPACK_STANZA_REGEX do
15
+ inject_into_file "config/webpacker.yml", before: BEFORE_TEST_STANZA_REGEX do
16
16
  <<~YAML
17
17
 
18
18
  # Used in conjunction with the test_data gem
19
19
  test_data:
20
20
  <<: *development
21
+
21
22
  YAML
22
23
  end
23
24
  end