test_data 0.0.2 → 0.2.2

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