database_cleaner_seeded 0.1.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e873ae11558480f4b079d70479f7679249459b62
4
+ data.tar.gz: f9b377a65d1711159ae9223f10a79379c00e787f
5
+ SHA512:
6
+ metadata.gz: e59a898857a331dd29464fbe0c4d8f37d822779d9258bd1cf04db3c87520187895b7cf02c2380789ba4dc5195cd8e8dcb5d38b871d9b81afda532bc3a31db278
7
+ data.tar.gz: b0c2fdb5a43c1039ecde219379fb852cdf8c93ed68b82310342fc63d69e71a549ed4385f96293d5905bc0e7a05e23443230e63f5529241be05bf195bbdeacb8b
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ database_cleaner_seeded (0.0.1)
5
+ activerecord
6
+ database_cleaner
7
+ rspec
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activemodel (5.0.0)
13
+ activesupport (= 5.0.0)
14
+ activerecord (5.0.0)
15
+ activemodel (= 5.0.0)
16
+ activesupport (= 5.0.0)
17
+ arel (~> 7.0)
18
+ activesupport (5.0.0)
19
+ concurrent-ruby (~> 1.0, >= 1.0.2)
20
+ i18n (~> 0.7)
21
+ minitest (~> 5.1)
22
+ tzinfo (~> 1.1)
23
+ arel (7.1.1)
24
+ concurrent-ruby (1.0.2)
25
+ database_cleaner (1.5.3)
26
+ diff-lcs (1.2.5)
27
+ i18n (0.7.0)
28
+ minitest (5.9.0)
29
+ rspec (3.5.0)
30
+ rspec-core (~> 3.5.0)
31
+ rspec-expectations (~> 3.5.0)
32
+ rspec-mocks (~> 3.5.0)
33
+ rspec-core (3.5.2)
34
+ rspec-support (~> 3.5.0)
35
+ rspec-expectations (3.5.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.5.0)
38
+ rspec-mocks (3.5.0)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.5.0)
41
+ rspec-support (3.5.0)
42
+ thread_safe (0.3.5)
43
+ tzinfo (1.2.2)
44
+ thread_safe (~> 0.1)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ database_cleaner_seeded!
51
+
52
+ BUNDLED WITH
53
+ 1.12.5
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Michael Dawson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # 'Seeded' strategy for Database Cleaner + Active Record
2
+
3
+ Restore the database to a seeded state between tests, in a way that's compatible with feature tests that are run in multiple threads.
4
+
5
+ ## Why?
6
+
7
+ The fantastic DatabaseCleaner gem provides a range of strategies for cleaning your database between RSpec tests. The gem's 'transaction' strategy is a fast way to rollback database state, and can be used to rollback your database state to a seeded baseline between tests. However, it isn't compatible with tests that run with multiple threads (e.g. using Capybara + Selenium), and so to make seed data available for these tests, you may need to run seed code before each test case.
8
+
9
+ This gem allows you to restore the database to a seeded state using direct DBMS operations (using raw SQL) instead of ruby code. If you have a test suite with a large reliance on seeded data, this gem may speed up your test suite. I've seen speed benefits of up to 30% with some projects.
10
+
11
+ ## How?
12
+
13
+ Before your feature test suite runs, a code block is run once to generate a raw seeds file. Then, before each test is run, your database is restored using direct injection of those seeds. This is usually faster than generating seeds using Ruby and inserting them individually before each test... but, because of the overhead associated with this approach, YMMV.
14
+
15
+ Currently, this gem only supports MYSQL, and doesn't support database connections that require a password.
16
+
17
+ To get started, add this gem to your Gemfile, point it to a method to call to call to setup your feature test seeds, and add some setup code to your `spec/rails_helper.rb` file.
18
+
19
+ ```ruby
20
+ # Gemfile
21
+
22
+ gem 'database_cleaner_seeded'
23
+ ```
24
+
25
+ ```ruby
26
+ # spec/support/seed_data_helper.rb
27
+
28
+ def seed_for_every_test
29
+ seed_foos
30
+ seed_bars
31
+ seed_bazzes
32
+ end
33
+ ```
34
+
35
+ ```ruby
36
+ # spec/rails_helper.rb
37
+
38
+ # ...
39
+
40
+ Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
41
+
42
+ require 'database_cleaner/active_record/seeded'
43
+
44
+ include SeedDataHelper
45
+
46
+ RSpec.configure do |config|
47
+ # ...
48
+
49
+ config.before(:suite) do
50
+ # Prepare the seeds file if we're running feature tests in this test run
51
+
52
+ if config.files_to_run.any? {|f| /spec\/features\//.match(f) }
53
+ DatabaseCleaner.prepare_with(:seeded) { seed_for_every_feature_test }
54
+ end
55
+ end
56
+
57
+ config.around(:each) do |example|
58
+ DatabaseCleaner.strategy = example.metadata[:type] == :feature ? :seeded : :transaction
59
+ DatabaseCleaner.cleaning { example.run }
60
+ end
61
+ end
62
+ ```
63
+
64
+ ## Options
65
+
66
+ With the above configuration, the code you run inside `DatabaseCleaner.prepare_with(:seeded)` is run each time you run your test suite with feature tests. However, depending on your requirements and the way that you run your test suite, you might like to skip seed regeneration between test runs, for faster performance. However - be warned! Use with caution - if you change your data model and don't regenerate the seeds, you might experience failures that are hard to diagnose.
67
+
68
+ This gem exposes an option for you to selectively skip seed regeneration, in the form of a proc. You may also override the seeds file path (`tmp/tmp/database_cleaner_seeds.sql` by default).
69
+
70
+ ```ruby
71
+ DatabaseCleaner::Seeded.configure do |config|
72
+ config.skip_seed_regeneration = -> { ! ENV['RESEED'] }
73
+ config.seeds_file_path = 'spec/fixtures/feature_test_seeds.sql'
74
+ end
75
+ ```
76
+
77
+ Using this configuration, existing seeds will be used between test suite runs. But, running `RESEED=true rspec spec/features` will force regeneration of the seeds.
78
+
79
+ ## Todo
80
+
81
+ - Add support for other DBMSs
82
+ - Add in some integration tests - perhaps with a mounted test application
83
+ - Profit
84
+
85
+ ## Development & Feedback
86
+
87
+ Have questions or encountered problems? Please use the
88
+ [issue tracker](https://github.com/michaeldawson/database_cleaner_seeded/issues). If you would like to contribute to this project, fork this repository, then run `bundle` and `rake` to run the tests. Pull requests appreciated.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Run RSpec'
6
+
7
+ RSpec::Core::RakeTask.new do |t|
8
+ t.verbose = false
9
+ end
10
+
11
+ task default: :spec
Binary file
@@ -0,0 +1,19 @@
1
+ require 'rake'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'database_cleaner_seeded'
5
+ s.version = '0.1.4'
6
+ s.date = '2016-08-09'
7
+ s.summary = 'Seed database directly between feature tests'
8
+ s.description = 'Provide a strategy for injecting database seeds between feature tests, using the DBMS directly.'
9
+ s.authors = ['Michael Dawson']
10
+ s.email = 'email.michaeldawson@gmail.com'
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ s.homepage = 'https://github.com/michaeldawson/database_cleaner_seeded'
14
+ s.license = 'MIT'
15
+
16
+ s.add_dependency('database_cleaner', '>= 1.2.0')
17
+ s.add_dependency('activerecord', '> 3.0')
18
+ s.add_dependency('rspec')
19
+ end
@@ -0,0 +1,73 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Custom database cleaner strategy to restore the database to a seeded state
3
+ # for integration tests. Truncate the database, then execute a restore of
4
+ # seeds using the DBMS.
5
+ # -----------------------------------------------------------------------------
6
+
7
+ require 'database_cleaner/active_record/deletion'
8
+ require 'database_cleaner/active_record/seeded/adapter/mysql'
9
+ require 'database_cleaner/active_record/seeded/configuration'
10
+
11
+ module DatabaseCleaner
12
+ module ActiveRecord
13
+ class Seeded < Deletion
14
+ class << self
15
+ attr_writer :configuration
16
+
17
+ def configure
18
+ yield(configuration)
19
+ end
20
+
21
+ def configuration
22
+ @configuration ||= Configuration.new
23
+ end
24
+ end
25
+
26
+ def start
27
+ adapter.inject_seeds_from_fixtures_file
28
+ end
29
+
30
+ def prepare(&seed_data_proc)
31
+ generate_seeds(seed_data_proc) unless skip_seeds_generation?
32
+ clean
33
+ end
34
+
35
+ private
36
+
37
+ def adapter
38
+ @adapter ||= Adapter::MYSQL.new(seeds_file_path)
39
+ end
40
+
41
+ def generate_seeds(seed_data_proc)
42
+ ::ActiveRecord::Base.transaction { seed_data_proc.call }
43
+ adapter.dump_database_to_fixtures_file
44
+ end
45
+
46
+ # If the user has configured the gem to skip seeds generation, return
47
+ # true, but only if we already have a seeds file that we can use.
48
+ def skip_seeds_generation?
49
+ raise "The option for 'skip_seed_regeneration' must be a Proc" if skip_seeds_proc && !skip_seeds_proc.respond_to?(:call)
50
+ skip_seeds_proc.try(:call) && File.exists?(seeds_file_path)
51
+ end
52
+
53
+ def seeds_file_path
54
+ @seeds_file_path ||= self.class.configuration.seeds_file_path
55
+ end
56
+
57
+ def skip_seeds_proc
58
+ @skip_seeds_proc ||= self.class.configuration.skip_seed_regeneration
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ module DatabaseCleaner
65
+ class << self
66
+ def prepare_with(strategy, &block)
67
+ connections.each do |connection|
68
+ connection.strategy = strategy
69
+ connection.strategy.prepare(&block)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Adapter for dumping and restoring seeds to the database using MYSQL.
3
+ # Currently doesn't support connections that use passwords.
4
+ # -----------------------------------------------------------------------------
5
+
6
+ require 'database_cleaner/active_record/truncation'
7
+
8
+ module DatabaseCleaner
9
+ module ActiveRecord
10
+ class Seeded < Deletion # I hate this, but omitting it gives a superclass violation
11
+ module Adapter
12
+ class MYSQL
13
+ IGNORE_TABLES = %w(schema_migrations)
14
+
15
+ attr_reader :seeds_file_path
16
+
17
+ def initialize(seeds_file_path)
18
+ @seeds_file_path = seeds_file_path
19
+ end
20
+
21
+ def inject_seeds_from_fixtures_file
22
+ `mysql --user=#{user} --host=#{host} --port=#{port} --database=#{database} < #{seeds_file_path}`
23
+ end
24
+
25
+ def dump_database_to_fixtures_file
26
+ `mysqldump --user=#{user} --host=#{host} --port=#{port} --compact #{ignore_tables} --no-create-info=TRUE #{database} > #{seeds_file_path}`
27
+ end
28
+
29
+ private
30
+
31
+ def configuration
32
+ @configuration ||= ::ActiveRecord::Base.configurations['test']
33
+ end
34
+
35
+ def port
36
+ 3306
37
+ end
38
+
39
+ def user
40
+ @user ||= configuration['username'] || 'root'
41
+ end
42
+
43
+ def host
44
+ @host ||= configuration['host']
45
+ end
46
+
47
+ def database
48
+ @database ||= configuration['database']
49
+ end
50
+
51
+ def ignore_tables
52
+ IGNORE_TABLES.map { |table| "--ignore-table=#{[database, table].join('.')}" }.join(' ')
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,15 @@
1
+ module DatabaseCleaner
2
+ module ActiveRecord
3
+ class Seeded
4
+ class Configuration
5
+ DEFAULT_SEEDS_FILE_PATH = 'tmp/database_cleaner_seeds.sql'
6
+
7
+ attr_accessor :skip_seed_regeneration, :seeds_file_path
8
+
9
+ def initialize
10
+ @seeds_file_path = DEFAULT_SEEDS_FILE_PATH
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require 'database_cleaner/active_record/seeded'
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'database_cleaner/active_record/seeded/configuration'
3
+
4
+ describe DatabaseCleaner::ActiveRecord::Seeded::Configuration do
5
+ let(:config) { DatabaseCleaner::ActiveRecord::Seeded::Configuration.new }
6
+
7
+ describe '#skip_seed_regeneration=' do
8
+ it 'default value is nil' do
9
+ expect(config.skip_seed_regeneration).to be_nil
10
+ end
11
+
12
+ it 'can set value' do
13
+ value = Proc.new {}
14
+
15
+ config.skip_seed_regeneration = value
16
+ expect(config.skip_seed_regeneration).to eq(value)
17
+ end
18
+ end
19
+
20
+ describe '#seeds_file_path=' do
21
+ it "default value is 'tmp/database_cleaner_seeds.sql'" do
22
+ expect(config.seeds_file_path).to eq('tmp/database_cleaner_seeds.sql')
23
+ end
24
+
25
+ it 'can set value' do
26
+ value = 'spec/some/other/path'
27
+
28
+ config.seeds_file_path = value
29
+ expect(config.seeds_file_path).to eq(value)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ module DatabaseCleaner
4
+ module ActiveRecord
5
+ describe Seeded do
6
+ let(:connection) { double('connection') }
7
+ let(:adapter) {
8
+ DatabaseCleaner::ActiveRecord::Seeded::Adapter::MYSQL.new('foo')
9
+ }
10
+
11
+ before(:each) do
12
+ allow(connection).to receive(:disable_referential_integrity).and_yield
13
+ allow(connection).to receive(:database_cleaner_view_cache).and_return([])
14
+ allow(::ActiveRecord::Base).to receive(:connection).and_return(connection)
15
+ allow(connection).to receive(:delete_table)
16
+ allow(DatabaseCleaner::ActiveRecord::Seeded::Adapter::MYSQL)
17
+ .to receive(:new).and_return(adapter)
18
+ end
19
+
20
+ describe '#start' do
21
+ it 'sends a call to the adapter to inject seeds' do
22
+ expect(adapter).to receive(:inject_seeds_from_fixtures_file)
23
+
24
+ Seeded.new.start
25
+ end
26
+ end
27
+
28
+ describe '#prepare' do
29
+ before :each do
30
+ allow(connection).to receive(:database_cleaner_table_cache)
31
+ .and_return(%w[schema_migrations shoes hats])
32
+ allow(adapter).to receive(:dump_database_to_fixtures_file)
33
+
34
+ allow(connection).to receive(:transaction).and_yield
35
+ end
36
+
37
+ it 'deletes data in all tables except for schema_migrations' do
38
+ expect(connection).to receive(:delete_table).with('shoes')
39
+ expect(connection).to receive(:delete_table).with('hats')
40
+
41
+ Seeded.new.prepare {}
42
+ end
43
+
44
+ it 'asks the adapter to dump the database' do
45
+ expect(adapter).to receive(:dump_database_to_fixtures_file)
46
+
47
+ Seeded.new.prepare {}
48
+ end
49
+
50
+ it 'calls the seed data proc in the method' do
51
+ seed_data_spy = spy(:seed_proc)
52
+ expect(seed_data_spy).to receive(:call)
53
+
54
+ Seeded.new.prepare { seed_data_spy.call }
55
+ end
56
+
57
+ context "when the 'skip_seed_regeneration' proc has been set to something that returns true" do
58
+ let(:file_path) { 'some/file/path' }
59
+
60
+ before :each do
61
+ DatabaseCleaner::ActiveRecord::Seeded.configure do |config|
62
+ config.skip_seed_regeneration = -> { true }
63
+ config.seeds_file_path = file_path
64
+ end
65
+ end
66
+
67
+ context 'and the seeds fixture file already exists' do
68
+ before :each do
69
+ allow(File).to receive(:exists?)
70
+ .with(file_path).and_return(true)
71
+ end
72
+
73
+ it "doesn't call the seed data proc in the method" do
74
+ seed_data_spy = spy(:seed_proc)
75
+ expect(seed_data_spy).not_to receive(:call)
76
+
77
+ Seeded.new.prepare { seed_data_spy.call }
78
+ end
79
+ end
80
+
81
+ context "and the seeds fixture file doesn't already exist" do
82
+ before :each do
83
+ allow(File).to receive(:exists?)
84
+ .with(file_path).and_return(false)
85
+ end
86
+
87
+ it 'still calls the seed data proc in the method' do
88
+ seed_data_spy = spy(:seed_proc)
89
+ expect(seed_data_spy).to receive(:call)
90
+
91
+ Seeded.new.prepare { seed_data_spy.call }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'active_record'
5
+ require 'database_cleaner_seeded'
6
+
7
+ Bundler.require(:default)
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: database_cleaner_seeded
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Michael Dawson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: database_cleaner
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Provide a strategy for injecting database seeds between feature tests,
56
+ using the DBMS directly.
57
+ email: email.michaeldawson@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Gemfile
63
+ - Gemfile.lock
64
+ - LICENSE
65
+ - README.md
66
+ - Rakefile
67
+ - database_cleaner_seeded-0.1.2.gem
68
+ - database_cleaner_seeded.gemspec
69
+ - lib/database_cleaner/active_record/seeded.rb
70
+ - lib/database_cleaner/active_record/seeded/adapter/mysql.rb
71
+ - lib/database_cleaner/active_record/seeded/configuration.rb
72
+ - lib/database_cleaner_seeded.rb
73
+ - spec/database_cleaner/seeded/configuration_spec.rb
74
+ - spec/database_cleaner/seeded_spec.rb
75
+ - spec/spec_helper.rb
76
+ homepage: https://github.com/michaeldawson/database_cleaner_seeded
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.4
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Seed database directly between feature tests
100
+ test_files:
101
+ - spec/database_cleaner/seeded/configuration_spec.rb
102
+ - spec/database_cleaner/seeded_spec.rb
103
+ - spec/spec_helper.rb