test_data 0.0.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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