test_data 0.0.2 → 0.2.2

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -5
  3. data/.standard.yml +2 -0
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile.lock +16 -16
  6. data/LICENSE.txt +1 -6
  7. data/README.md +864 -501
  8. data/example/.gitignore +1 -4
  9. data/example/Gemfile.lock +74 -74
  10. data/example/config/application.rb +3 -0
  11. data/example/config/credentials.yml.enc +1 -2
  12. data/example/spec/rails_helper.rb +1 -1
  13. data/example/spec/requests/boops_spec.rb +1 -5
  14. data/example/spec/requests/rails_fixtures_override_spec.rb +106 -0
  15. data/example/test/integration/better_mode_switching_demo_test.rb +6 -10
  16. data/example/test/integration/fixture_load_count_test.rb +82 -0
  17. data/example/test/integration/load_rollback_truncate_test.rb +40 -45
  18. data/example/test/integration/mode_switching_demo_test.rb +4 -14
  19. data/example/test/integration/parallel_boops_with_fixtures_test.rb +2 -6
  20. data/example/test/integration/parallel_boops_without_fixtures_test.rb +2 -6
  21. data/example/test/integration/rails_fixtures_double_load_test.rb +10 -0
  22. data/example/test/integration/rails_fixtures_override_test.rb +110 -0
  23. data/example/test/integration/test_data_hooks_test.rb +89 -0
  24. data/example/test/integration/transaction_committing_boops_test.rb +5 -3
  25. data/example/test/test_helper.rb +2 -6
  26. data/lib/generators/test_data/cable_yaml_generator.rb +18 -0
  27. data/lib/generators/test_data/database_yaml_generator.rb +2 -3
  28. data/lib/generators/test_data/environment_file_generator.rb +7 -0
  29. data/lib/generators/test_data/initializer_generator.rb +20 -7
  30. data/lib/generators/test_data/secrets_yaml_generator.rb +19 -0
  31. data/lib/generators/test_data/webpacker_yaml_generator.rb +3 -2
  32. data/lib/test_data.rb +37 -1
  33. data/lib/test_data/active_record_ext.rb +11 -0
  34. data/lib/test_data/config.rb +33 -3
  35. data/lib/test_data/configurators.rb +2 -0
  36. data/lib/test_data/configurators/cable_yaml.rb +25 -0
  37. data/lib/test_data/configurators/environment_file.rb +3 -2
  38. data/lib/test_data/configurators/initializer.rb +3 -2
  39. data/lib/test_data/configurators/secrets_yaml.rb +25 -0
  40. data/lib/test_data/configurators/webpacker_yaml.rb +4 -3
  41. data/lib/test_data/custom_loaders/abstract_base.rb +25 -0
  42. data/lib/test_data/custom_loaders/rails_fixtures.rb +45 -0
  43. data/lib/test_data/dumps_database.rb +24 -1
  44. data/lib/test_data/generator_support.rb +3 -0
  45. data/lib/test_data/inserts_test_data.rb +25 -0
  46. data/lib/test_data/loads_database_dumps.rb +1 -1
  47. data/lib/test_data/log.rb +19 -1
  48. data/lib/test_data/{transactional_data_loader.rb → manager.rb} +78 -81
  49. data/lib/test_data/rake.rb +16 -7
  50. data/lib/test_data/statistics.rb +6 -1
  51. data/lib/test_data/truncates_test_data.rb +31 -0
  52. data/lib/test_data/version.rb +1 -1
  53. data/script/reset_example_app +1 -0
  54. data/script/test +31 -6
  55. data/test_data.gemspec +1 -1
  56. metadata +20 -4
@@ -3,18 +3,20 @@ require "test_helper"
3
3
  class TransactionCommittingTestCase < ActiveSupport::TestCase
4
4
  self.use_transactional_tests = false
5
5
 
6
- def setup
6
+ setup do
7
7
  Noncommittal.stop!
8
- TestData.load(transactions: false)
8
+ TestData.insert_test_data_dump
9
9
  end
10
10
 
11
- def teardown
11
+ teardown do
12
12
  Boop.delete_all
13
13
  Noncommittal.start!
14
14
  end
15
15
  end
16
16
 
17
17
  class TransactionCommittingBoopsTest < TransactionCommittingTestCase
18
+ i_suck_and_my_tests_are_order_dependent!
19
+
18
20
  def test_finds_the_boops
19
21
  assert_equal 15, Boop.count
20
22
  end
@@ -8,11 +8,7 @@ class SerializedNonTransactionalTestCase < ActiveSupport::TestCase
8
8
  parallelize(workers: 1)
9
9
  self.use_transactional_tests = false
10
10
 
11
- def setup
12
- TestData.load
13
- end
14
-
15
- def teardown
16
- TestData.rollback
11
+ setup do
12
+ TestData.uses_test_data
17
13
  end
18
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
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,12 +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
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
10
17
  config.active_record.dump_schema_after_migration = false
11
18
  end
12
19
  RUBY
@@ -1,4 +1,5 @@
1
1
  require "rails/generators"
2
+ require_relative "../../test_data/generator_support"
2
3
 
3
4
  module TestData
4
5
  class InitializerGenerator < Rails::Generators::Base
@@ -7,14 +8,17 @@ module TestData
7
8
  return unless defined?(TestData)
8
9
 
9
10
  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"
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 { }
12
14
 
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
+ # 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 { }
15
18
 
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"
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 { }
18
22
 
19
23
  # Tables whose data shouldn't be loaded into tests.
20
24
  # ("ar_internal_metadata" and "schema_migrations" are always excluded)
@@ -23,7 +27,16 @@ module TestData
23
27
  # Tables whose data should be excluded from SQL dumps (still dumps their schema DDL)
24
28
  # config.dont_dump_these_tables = []
25
29
 
26
- # Tables whose data should be truncated by TestData.truncate
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
27
40
  # If left as `nil`, all tables inserted into by the SQL file at
28
41
  # `data_dump_path` will be truncated
29
42
  # config.truncate_these_test_data_tables = nil
@@ -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,9 +1,9 @@
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?
@@ -12,12 +12,13 @@ module TestData
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
data/lib/test_data.rb CHANGED
@@ -1,25 +1,61 @@
1
+ require_relative "test_data/active_record_ext"
1
2
  require_relative "test_data/active_support_ext"
2
3
  require_relative "test_data/config"
3
4
  require_relative "test_data/configuration_verification"
4
5
  require_relative "test_data/configurators"
5
6
  require_relative "test_data/configurators/environment_file"
6
7
  require_relative "test_data/configurators/initializer"
8
+ require_relative "test_data/configurators/cable_yaml"
7
9
  require_relative "test_data/configurators/database_yaml"
10
+ require_relative "test_data/configurators/secrets_yaml"
8
11
  require_relative "test_data/configurators/webpacker_yaml"
12
+ require_relative "test_data/custom_loaders/abstract_base"
13
+ require_relative "test_data/custom_loaders/rails_fixtures"
9
14
  require_relative "test_data/detects_database_emptiness"
10
15
  require_relative "test_data/dumps_database"
11
16
  require_relative "test_data/error"
17
+ require_relative "test_data/inserts_test_data"
12
18
  require_relative "test_data/installs_configuration"
13
19
  require_relative "test_data/loads_database_dumps"
14
20
  require_relative "test_data/log"
15
21
  require_relative "test_data/railtie"
16
22
  require_relative "test_data/save_point"
17
23
  require_relative "test_data/statistics"
18
- require_relative "test_data/transactional_data_loader"
24
+ require_relative "test_data/manager"
25
+ require_relative "test_data/truncates_test_data"
19
26
  require_relative "test_data/verifies_configuration"
20
27
  require_relative "test_data/verifies_dumps_are_loadable"
21
28
  require_relative "test_data/version"
22
29
  require_relative "generators/test_data/environment_file_generator"
23
30
  require_relative "generators/test_data/initializer_generator"
31
+ require_relative "generators/test_data/cable_yaml_generator"
24
32
  require_relative "generators/test_data/database_yaml_generator"
33
+ require_relative "generators/test_data/secrets_yaml_generator"
25
34
  require_relative "generators/test_data/webpacker_yaml_generator"
35
+
36
+ module TestData
37
+ def self.uninitialize
38
+ @manager ||= Manager.new
39
+ @manager.rollback_to_before_data_load
40
+ end
41
+
42
+ def self.uses_test_data
43
+ @manager ||= Manager.new
44
+ @manager.load
45
+ end
46
+
47
+ def self.uses_clean_slate
48
+ @manager ||= Manager.new
49
+ @manager.truncate
50
+ end
51
+
52
+ def self.uses_rails_fixtures(test_instance)
53
+ @rails_fixtures_loader ||= CustomLoaders::RailsFixtures.new
54
+ @manager ||= Manager.new
55
+ @manager.load_custom_data(@rails_fixtures_loader, test_instance: test_instance)
56
+ end
57
+
58
+ def self.insert_test_data_dump
59
+ InsertsTestData.new.call
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ module TestData
2
+ def self.prevent_rails_fixtures_from_loading_automatically!
3
+ ActiveRecord::TestFixtures.define_method(:__test_data_gem_setup_fixtures,
4
+ ActiveRecord::TestFixtures.instance_method(:setup_fixtures))
5
+ ActiveRecord::TestFixtures.remove_method(:setup_fixtures)
6
+ ActiveRecord::TestFixtures.define_method(:setup_fixtures, ->(config = nil) {})
7
+
8
+ ActiveRecord::TestFixtures.remove_method(:teardown_fixtures)
9
+ ActiveRecord::TestFixtures.define_method(:teardown_fixtures, -> {})
10
+ end
11
+ end
@@ -29,7 +29,7 @@ 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.truncate is called
32
+ # Tables to truncate when TestData.uses_clean_slate is called
33
33
  attr_accessor :truncate_these_test_data_tables
34
34
 
35
35
  # Log level (valid values: [:debug, :info, :warn, :error, :quiet])
@@ -41,7 +41,8 @@ module TestData
41
41
  TestData.log.level = level
42
42
  end
43
43
 
44
- attr_reader :pwd, :database_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
45
46
 
46
47
  def self.full_path_reader(*relative_path_readers)
47
48
  relative_path_readers.each do |relative_path_reader|
@@ -51,17 +52,46 @@ module TestData
51
52
  end
52
53
  end
53
54
 
54
- full_path_reader :schema_dump_path, :data_dump_path, :non_test_data_dump_path, :database_yaml_path
55
+ full_path_reader :schema_dump_path, :data_dump_path, :non_test_data_dump_path, :cable_yaml_path, :database_yaml_path, :secrets_yaml_path
55
56
 
56
57
  def initialize(pwd:)
57
58
  @pwd = pwd
58
59
  @schema_dump_path = "test/support/test_data/schema.sql"
59
60
  @data_dump_path = "test/support/test_data/data.sql"
60
61
  @non_test_data_dump_path = "test/support/test_data/non_test_data.sql"
62
+ @cable_yaml_path = "config/cable.yml"
61
63
  @database_yaml_path = "config/database.yml"
64
+ @secrets_yaml_path = "config/secrets.yml"
62
65
  @non_test_data_tables = []
63
66
  @dont_dump_these_tables = []
64
67
  @truncate_these_test_data_tables = nil
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
65
95
  end
66
96
 
67
97
  def database_yaml
@@ -4,7 +4,9 @@ module TestData
4
4
  [
5
5
  EnvironmentFile,
6
6
  Initializer,
7
+ CableYaml,
7
8
  DatabaseYaml,
9
+ SecretsYaml,
8
10
  WebpackerYaml
9
11
  ].map(&:new)
10
12
  end
@@ -0,0 +1,25 @@
1
+ module TestData
2
+ module Configurators
3
+ class CableYaml
4
+ def initialize
5
+ @generator = CableYamlGenerator.new
6
+ @config = TestData.config
7
+ end
8
+
9
+ def verify
10
+ if !File.exist?(@config.cable_yaml_full_path) ||
11
+ YAML.load_file(@config.cable_yaml_full_path).key?("test_data")
12
+ ConfigurationVerification.new(looks_good?: true)
13
+ else
14
+ ConfigurationVerification.new(problems: [
15
+ "'#{@config.cable_yaml_path}' exists but does not contain a 'test_data' section"
16
+ ])
17
+ end
18
+ end
19
+
20
+ def configure
21
+ @generator.call
22
+ end
23
+ end
24
+ end
25
+ end
@@ -7,12 +7,13 @@ module TestData
7
7
  end
8
8
 
9
9
  def verify
10
- pathname = Pathname.new("#{@config.pwd}/config/environments/test_data.rb")
10
+ path = "config/environments/test_data.rb"
11
+ pathname = Pathname.new("#{@config.pwd}/#{path}")
11
12
  if pathname.readable?
12
13
  ConfigurationVerification.new(looks_good?: true)
13
14
  else
14
15
  ConfigurationVerification.new(problems: [
15
- "'#{pathname}' is not readable"
16
+ "'#{path}' is not readable"
16
17
  ])
17
18
  end
18
19
  end
@@ -7,12 +7,13 @@ module TestData
7
7
  end
8
8
 
9
9
  def verify
10
- pathname = Pathname.new("#{@config.pwd}/config/initializers/test_data.rb")
10
+ path = "config/initializers/test_data.rb"
11
+ pathname = Pathname.new("#{@config.pwd}/#{path}")
11
12
  if pathname.readable?
12
13
  ConfigurationVerification.new(looks_good?: true)
13
14
  else
14
15
  ConfigurationVerification.new(problems: [
15
- "'#{pathname}' is not readable"
16
+ "'#{path}' is not readable"
16
17
  ])
17
18
  end
18
19
  end
@@ -0,0 +1,25 @@
1
+ module TestData
2
+ module Configurators
3
+ class SecretsYaml
4
+ def initialize
5
+ @generator = SecretsYamlGenerator.new
6
+ @config = TestData.config
7
+ end
8
+
9
+ def verify
10
+ if !File.exist?(@config.secrets_yaml_full_path) ||
11
+ YAML.load_file(@config.secrets_yaml_full_path).key?("test_data")
12
+ ConfigurationVerification.new(looks_good?: true)
13
+ else
14
+ ConfigurationVerification.new(problems: [
15
+ "'#{@config.secrets_yaml_path}' exists but does not contain a 'test_data' section"
16
+ ])
17
+ end
18
+ end
19
+
20
+ def configure
21
+ @generator.call
22
+ end
23
+ end
24
+ end
25
+ end
@@ -7,16 +7,17 @@ module TestData
7
7
  end
8
8
 
9
9
  def verify
10
- pathname = Pathname.new("#{@config.pwd}/config/webpacker.yml")
10
+ path = "config/webpacker.yml"
11
+ pathname = Pathname.new("#{@config.pwd}/#{path}")
11
12
  return ConfigurationVerification.new(looks_good?: true) unless pathname.readable?
12
13
  yaml = load_yaml(pathname)
13
14
  if yaml.nil?
14
15
  ConfigurationVerification.new(problems: [
15
- "'#{pathname}' is not valid YAML"
16
+ "'#{path}' is not valid YAML"
16
17
  ])
17
18
  elsif !yaml.key?("test_data")
18
19
  ConfigurationVerification.new(problems: [
19
- "'#{pathname}' does not contain a 'test_data' section"
20
+ "'#{path}' does not contain a 'test_data' section"
20
21
  ])
21
22
  else
22
23
  ConfigurationVerification.new(looks_good?: true)