database_cleaner 0.5.2 → 0.6.0.rc.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.
- data/Gemfile.lock +145 -0
- data/History.txt +24 -1
- data/README.textile +48 -0
- data/Rakefile +4 -0
- data/TODO +3 -0
- data/VERSION.yml +3 -2
- data/examples/Gemfile +46 -0
- data/examples/Gemfile.lock +145 -0
- data/examples/config/database.yml +7 -0
- data/examples/config/database.yml.example +8 -0
- data/examples/db/activerecord_one.db +0 -0
- data/examples/db/activerecord_two.db +0 -0
- data/examples/db/datamapper_default.db +0 -0
- data/examples/db/datamapper_one.db +0 -0
- data/examples/db/datamapper_two.db +0 -0
- data/examples/db/sqlite_databases_go_here +0 -0
- data/examples/features/example_multiple_db.feature +23 -0
- data/examples/features/example_multiple_orm.feature +22 -0
- data/examples/features/step_definitions/activerecord_steps.rb +31 -0
- data/examples/features/step_definitions/couchpotato_steps.rb +31 -0
- data/examples/features/step_definitions/datamapper_steps.rb +37 -0
- data/examples/features/step_definitions/mongoid_steps.rb +23 -0
- data/examples/features/step_definitions/mongomapper_steps.rb +31 -0
- data/examples/features/step_definitions/translation_steps.rb +55 -0
- data/examples/features/support/env.rb +49 -10
- data/examples/lib/activerecord_models.rb +34 -5
- data/examples/lib/couchpotato_models.rb +46 -6
- data/examples/lib/datamapper_models.rb +37 -3
- data/examples/lib/mongoid_models.rb +28 -2
- data/examples/lib/mongomapper_models.rb +35 -1
- data/features/cleaning_multiple_dbs.feature +20 -0
- data/features/cleaning_multiple_orms.feature +29 -0
- data/features/step_definitions/database_cleaner_steps.rb +20 -13
- data/features/support/feature_runner.rb +39 -0
- data/lib/database_cleaner/active_record/base.rb +46 -0
- data/lib/database_cleaner/active_record/transaction.rb +10 -10
- data/lib/database_cleaner/active_record/truncation.rb +17 -7
- data/lib/database_cleaner/base.rb +129 -0
- data/lib/database_cleaner/configuration.rb +45 -97
- data/lib/database_cleaner/couch_potato/base.rb +7 -0
- data/lib/database_cleaner/couch_potato/truncation.rb +4 -2
- data/lib/database_cleaner/cucumber.rb +0 -1
- data/lib/database_cleaner/data_mapper/base.rb +21 -0
- data/lib/database_cleaner/data_mapper/transaction.rb +10 -5
- data/lib/database_cleaner/data_mapper/truncation.rb +52 -19
- data/lib/database_cleaner/generic/base.rb +23 -0
- data/lib/database_cleaner/generic/truncation.rb +43 -0
- data/lib/database_cleaner/mongo_mapper/base.rb +20 -0
- data/lib/database_cleaner/mongo_mapper/truncation.rb +9 -3
- data/lib/database_cleaner/mongoid/base.rb +20 -0
- data/lib/database_cleaner/mongoid/truncation.rb +9 -5
- data/spec/database_cleaner/active_record/base_spec.rb +130 -0
- data/spec/database_cleaner/active_record/truncation_spec.rb +19 -18
- data/spec/database_cleaner/base_spec.rb +441 -0
- data/spec/database_cleaner/configuration_spec.rb +255 -68
- data/spec/database_cleaner/couch_potato/truncation_spec.rb +4 -3
- data/spec/database_cleaner/data_mapper/base_spec.rb +30 -0
- data/spec/database_cleaner/data_mapper/transaction_spec.rb +23 -0
- data/spec/database_cleaner/data_mapper/truncation_spec.rb +11 -0
- data/spec/database_cleaner/generic/base_spec.rb +22 -0
- data/spec/database_cleaner/generic/truncation_spec.rb +68 -0
- data/spec/database_cleaner/mongo_mapper/base_spec.rb +33 -0
- data/spec/database_cleaner/mongo_mapper/mongo_examples.rb +8 -0
- data/spec/database_cleaner/mongo_mapper/truncation_spec.rb +11 -18
- data/spec/database_cleaner/shared_strategy_spec.rb +13 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -3
- metadata +76 -8
- data/examples/features/step_definitions/example_steps.rb +0 -8
- data/lib/database_cleaner/truncation_base.rb +0 -41
@@ -1,129 +1,77 @@
|
|
1
|
+
require 'database_cleaner/base'
|
2
|
+
|
1
3
|
module DatabaseCleaner
|
2
4
|
|
3
5
|
class NoStrategySetError < StandardError; end
|
4
6
|
class NoORMDetected < StandardError; end
|
5
7
|
class UnknownStrategySpecified < ArgumentError; end
|
6
8
|
|
7
|
-
|
8
|
-
def
|
9
|
-
|
9
|
+
class << self
|
10
|
+
def [](orm,opts = {})
|
11
|
+
raise NoORMDetected if orm.nil?
|
12
|
+
@connections ||= []
|
13
|
+
cleaner = DatabaseCleaner::Base.new(orm,opts)
|
14
|
+
connections.push cleaner
|
15
|
+
cleaner
|
10
16
|
end
|
11
|
-
end
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
%w[truncation transaction]
|
18
|
+
def app_root=(desired_root)
|
19
|
+
@app_root = desired_root
|
16
20
|
end
|
17
|
-
end
|
18
|
-
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
%w[truncation]
|
22
|
+
def app_root
|
23
|
+
@app_root || Dir.pwd
|
23
24
|
end
|
24
|
-
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
%w[truncation]
|
26
|
+
def connections
|
27
|
+
@connections ||= [::DatabaseCleaner::Base.new]
|
29
28
|
end
|
30
|
-
end
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
def strategy=(stratagem)
|
31
|
+
self.connections.each { |connect| connect.strategy = stratagem }
|
32
|
+
remove_duplicates
|
35
33
|
end
|
36
|
-
end
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
strategy, *strategy_args = args
|
42
|
-
orm_strategy(strategy).new(*strategy_args)
|
43
|
-
end
|
44
|
-
|
45
|
-
def clean_with(*args)
|
46
|
-
strategy = create_strategy(*args)
|
47
|
-
strategy.clean
|
48
|
-
strategy
|
49
|
-
end
|
50
|
-
|
51
|
-
alias clean_with! clean_with
|
52
|
-
|
53
|
-
def strategy=(args)
|
54
|
-
strategy, *strategy_args = args
|
55
|
-
if strategy.is_a?(Symbol)
|
56
|
-
@strategy = create_strategy(*args)
|
57
|
-
elsif strategy_args.empty?
|
58
|
-
@strategy = strategy
|
59
|
-
else
|
60
|
-
raise ArgumentError, "You must provide a strategy object, or a symbol for a know strategy along with initialization params."
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def orm=(orm_string)
|
65
|
-
@orm = orm_string
|
35
|
+
def orm=(orm)
|
36
|
+
self.connections.each { |connect| connect.orm = orm }
|
37
|
+
remove_duplicates
|
66
38
|
end
|
67
39
|
|
68
40
|
def start
|
69
|
-
|
41
|
+
self.connections.each { |connection| connection.start }
|
70
42
|
end
|
71
43
|
|
72
44
|
def clean
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
alias clean! clean
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def strategy
|
81
|
-
return @strategy if @strategy
|
82
|
-
raise NoStrategySetError, "Please set a strategy with DatabaseCleaner.strategy=."
|
45
|
+
self.connections.each { |connection| connection.clean }
|
83
46
|
end
|
84
47
|
|
85
|
-
def
|
86
|
-
|
87
|
-
orm_module.const_get(strategy.to_s.capitalize)
|
88
|
-
rescue LoadError => e
|
89
|
-
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}"
|
48
|
+
def clean_with(stratagem)
|
49
|
+
self.connections.each { |connection| connection.clean_with stratagem }
|
90
50
|
end
|
91
51
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
'active_record'
|
97
|
-
elsif defined? ::DataMapper
|
98
|
-
'data_mapper'
|
99
|
-
elsif defined? ::MongoMapper
|
100
|
-
'mongo_mapper'
|
101
|
-
elsif defined? ::Mongoid
|
102
|
-
'mongoid'
|
103
|
-
elsif defined? ::CouchPotato
|
104
|
-
'couch_potato'
|
105
|
-
else
|
106
|
-
raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, MongoMapper, Mongoid, or CouchPotato loaded?"
|
107
|
-
end
|
52
|
+
def remove_duplicates
|
53
|
+
temp = []
|
54
|
+
self.connections.each do |connect|
|
55
|
+
temp.push connect unless temp.include? connect
|
108
56
|
end
|
57
|
+
@connections = temp
|
109
58
|
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
59
|
+
|
60
|
+
def orm_module(symbol)
|
61
|
+
case symbol
|
62
|
+
when :active_record
|
63
|
+
DatabaseCleaner::ActiveRecord
|
64
|
+
when :data_mapper
|
65
|
+
DatabaseCleaner::DataMapper
|
66
|
+
when :mongo
|
67
|
+
DatabaseCleaner::Mongo
|
68
|
+
when :mongoid
|
69
|
+
DatabaseCleaner::Mongoid
|
70
|
+
when :mongo_mapper
|
71
|
+
DatabaseCleaner::MongoMapper
|
72
|
+
when :couch_potato
|
73
|
+
DatabaseCleaner::CouchPotato
|
124
74
|
end
|
125
75
|
end
|
126
|
-
|
127
76
|
end
|
128
|
-
|
129
77
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
require 'database_cleaner/
|
1
|
+
require 'database_cleaner/generic/truncation'
|
2
2
|
|
3
3
|
module DatabaseCleaner
|
4
4
|
module CouchPotato
|
5
|
-
class Truncation
|
5
|
+
class Truncation
|
6
|
+
include ::DatabaseCleaner::Generic::Truncation
|
7
|
+
|
6
8
|
def initialize(options = {})
|
7
9
|
if options.has_key?(:only) || options.has_key?(:except)
|
8
10
|
raise ArgumentError, "The :only and :except options are not available for use with CouchPotato/CouchDB."
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'database_cleaner/generic/base'
|
2
|
+
module DatabaseCleaner
|
3
|
+
module DataMapper
|
4
|
+
def self.available_strategies
|
5
|
+
%w[truncation transaction]
|
6
|
+
end
|
7
|
+
|
8
|
+
module Base
|
9
|
+
include ::DatabaseCleaner::Generic::Base
|
10
|
+
|
11
|
+
def db=(desired_db)
|
12
|
+
@db = desired_db
|
13
|
+
end
|
14
|
+
|
15
|
+
def db
|
16
|
+
@db || :default
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,16 +1,21 @@
|
|
1
|
+
require 'database_cleaner/data_mapper/base'
|
2
|
+
|
1
3
|
module DatabaseCleaner::DataMapper
|
2
4
|
class Transaction
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
include ::DatabaseCleaner::DataMapper::Base
|
6
|
+
#TODO Figure out repositories, may have to refactor connection_klass to something more sensible
|
7
|
+
def start(repository = nil)
|
8
|
+
repository = self.db if repository.nil?
|
9
|
+
::DataMapper.repository(repository) do |r|
|
6
10
|
transaction = DataMapper::Transaction.new(r)
|
7
11
|
transaction.begin
|
8
12
|
r.adapter.push_transaction(transaction)
|
9
13
|
end
|
10
14
|
end
|
11
15
|
|
12
|
-
def clean(
|
13
|
-
|
16
|
+
def clean(repository = nil)
|
17
|
+
repository = self.db if repository.nil?
|
18
|
+
::DataMapper.repository(repository) do |r|
|
14
19
|
adapter = r.adapter
|
15
20
|
while adapter.current_transaction
|
16
21
|
adapter.current_transaction.rollback
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require "database_cleaner/
|
1
|
+
require "database_cleaner/generic/truncation"
|
2
|
+
require 'database_cleaner/data_mapper/base'
|
2
3
|
|
3
4
|
module DataMapper
|
4
5
|
module Adapters
|
@@ -29,12 +30,13 @@ module DataMapper
|
|
29
30
|
execute("SET FOREIGN_KEY_CHECKS = 0;")
|
30
31
|
yield
|
31
32
|
ensure
|
32
|
-
execute("SET FOREIGN_KEY_CHECKS = #{old};")
|
33
|
+
execute("SET FOREIGN_KEY_CHECKS = #{old.first};")
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
37
|
end
|
37
38
|
|
39
|
+
|
38
40
|
class Sqlite3Adapter < DataObjectsAdapter
|
39
41
|
|
40
42
|
# taken from http://github.com/godfat/dm-mapping/tree/master
|
@@ -46,7 +48,7 @@ module DataMapper
|
|
46
48
|
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
47
49
|
SQL
|
48
50
|
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 181
|
49
|
-
select
|
51
|
+
select(sql)
|
50
52
|
end
|
51
53
|
|
52
54
|
def truncate_table(table_name)
|
@@ -61,7 +63,32 @@ module DataMapper
|
|
61
63
|
end
|
62
64
|
|
63
65
|
end
|
66
|
+
|
67
|
+
class SqliteAdapter < DataObjectsAdapter
|
68
|
+
# taken from http://github.com/godfat/dm-mapping/tree/master
|
69
|
+
def storage_names(repository = :default)
|
70
|
+
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 177
|
71
|
+
sql = <<-SQL.compress_lines
|
72
|
+
SELECT name
|
73
|
+
FROM sqlite_master
|
74
|
+
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
75
|
+
SQL
|
76
|
+
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 181
|
77
|
+
select(sql)
|
78
|
+
end
|
64
79
|
|
80
|
+
def truncate_table(table_name)
|
81
|
+
execute("DELETE FROM #{quote_name(table_name)};")
|
82
|
+
end
|
83
|
+
|
84
|
+
# this is a no-op copied from activerecord
|
85
|
+
# i didn't find out if/how this is possible
|
86
|
+
# activerecord also doesn't do more here
|
87
|
+
def disable_referential_integrity
|
88
|
+
yield
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
65
92
|
|
66
93
|
# FIXME
|
67
94
|
# i don't know if this works
|
@@ -115,28 +142,34 @@ module DataMapper
|
|
115
142
|
end
|
116
143
|
|
117
144
|
|
118
|
-
module DatabaseCleaner
|
119
|
-
|
145
|
+
module DatabaseCleaner
|
146
|
+
module DataMapper
|
147
|
+
class Truncation
|
148
|
+
include ::DatabaseCleaner::DataMapper::Base
|
149
|
+
include ::DatabaseCleaner::Generic::Truncation
|
120
150
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
151
|
+
def clean(repository = nil)
|
152
|
+
repository = self.db if repository.nil?
|
153
|
+
adapter = ::DataMapper.repository(repository).adapter
|
154
|
+
adapter.disable_referential_integrity do
|
155
|
+
tables_to_truncate(repository).each do |table_name|
|
156
|
+
adapter.truncate_table table_name
|
157
|
+
end
|
126
158
|
end
|
127
159
|
end
|
128
|
-
end
|
129
160
|
|
130
|
-
|
161
|
+
private
|
131
162
|
|
132
|
-
|
133
|
-
|
134
|
-
|
163
|
+
def tables_to_truncate(repository = nil)
|
164
|
+
repository = self.db if repository.nil?
|
165
|
+
(@only || ::DataMapper.repository(repository).adapter.storage_names(repository)) - @tables_to_exclude
|
166
|
+
end
|
135
167
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
168
|
+
# overwritten
|
169
|
+
def migration_storage_name
|
170
|
+
'migration_info'
|
171
|
+
end
|
140
172
|
|
173
|
+
end
|
141
174
|
end
|
142
175
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ::DatabaseCleaner
|
2
|
+
module Generic
|
3
|
+
module Base
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
base.send(:include, InstanceMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
def db
|
12
|
+
:default
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def available_strategies
|
18
|
+
%W[]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module DatabaseCleaner
|
2
|
+
module Generic
|
3
|
+
module Truncation
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def initialize(opts={})
|
10
|
+
if !opts.empty? && !(opts.keys - [:only, :except]).empty?
|
11
|
+
raise ArgumentError, "The only valid options are :only and :except. You specified #{opts.keys.join(',')}."
|
12
|
+
end
|
13
|
+
if opts.has_key?(:only) && opts.has_key?(:except)
|
14
|
+
raise ArgumentError, "You may only specify either :only or :either. Doing both doesn't really make sense does it?"
|
15
|
+
end
|
16
|
+
|
17
|
+
@only = opts[:only]
|
18
|
+
@tables_to_exclude = (opts[:except] || [])
|
19
|
+
@tables_to_exclude << migration_storage_name unless migration_storage_name.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
#included for compatability reasons, do nothing if you don't need to
|
24
|
+
end
|
25
|
+
|
26
|
+
def clean
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def tables_to_truncate
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
34
|
+
|
35
|
+
# overwrite in subclasses
|
36
|
+
# default implementation given because migration storage need not be present
|
37
|
+
def migration_storage_name
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'database_cleaner/generic/base'
|
2
|
+
module DatabaseCleaner
|
3
|
+
module MongoMapper
|
4
|
+
def self.available_strategies
|
5
|
+
%w[truncation]
|
6
|
+
end
|
7
|
+
|
8
|
+
module Base
|
9
|
+
include ::DatabaseCleaner::Generic::Base
|
10
|
+
|
11
|
+
def db=(desired_db)
|
12
|
+
@db = desired_db
|
13
|
+
end
|
14
|
+
|
15
|
+
def db
|
16
|
+
@db || :default
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|