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.
Files changed (71) hide show
  1. data/Gemfile.lock +145 -0
  2. data/History.txt +24 -1
  3. data/README.textile +48 -0
  4. data/Rakefile +4 -0
  5. data/TODO +3 -0
  6. data/VERSION.yml +3 -2
  7. data/examples/Gemfile +46 -0
  8. data/examples/Gemfile.lock +145 -0
  9. data/examples/config/database.yml +7 -0
  10. data/examples/config/database.yml.example +8 -0
  11. data/examples/db/activerecord_one.db +0 -0
  12. data/examples/db/activerecord_two.db +0 -0
  13. data/examples/db/datamapper_default.db +0 -0
  14. data/examples/db/datamapper_one.db +0 -0
  15. data/examples/db/datamapper_two.db +0 -0
  16. data/examples/db/sqlite_databases_go_here +0 -0
  17. data/examples/features/example_multiple_db.feature +23 -0
  18. data/examples/features/example_multiple_orm.feature +22 -0
  19. data/examples/features/step_definitions/activerecord_steps.rb +31 -0
  20. data/examples/features/step_definitions/couchpotato_steps.rb +31 -0
  21. data/examples/features/step_definitions/datamapper_steps.rb +37 -0
  22. data/examples/features/step_definitions/mongoid_steps.rb +23 -0
  23. data/examples/features/step_definitions/mongomapper_steps.rb +31 -0
  24. data/examples/features/step_definitions/translation_steps.rb +55 -0
  25. data/examples/features/support/env.rb +49 -10
  26. data/examples/lib/activerecord_models.rb +34 -5
  27. data/examples/lib/couchpotato_models.rb +46 -6
  28. data/examples/lib/datamapper_models.rb +37 -3
  29. data/examples/lib/mongoid_models.rb +28 -2
  30. data/examples/lib/mongomapper_models.rb +35 -1
  31. data/features/cleaning_multiple_dbs.feature +20 -0
  32. data/features/cleaning_multiple_orms.feature +29 -0
  33. data/features/step_definitions/database_cleaner_steps.rb +20 -13
  34. data/features/support/feature_runner.rb +39 -0
  35. data/lib/database_cleaner/active_record/base.rb +46 -0
  36. data/lib/database_cleaner/active_record/transaction.rb +10 -10
  37. data/lib/database_cleaner/active_record/truncation.rb +17 -7
  38. data/lib/database_cleaner/base.rb +129 -0
  39. data/lib/database_cleaner/configuration.rb +45 -97
  40. data/lib/database_cleaner/couch_potato/base.rb +7 -0
  41. data/lib/database_cleaner/couch_potato/truncation.rb +4 -2
  42. data/lib/database_cleaner/cucumber.rb +0 -1
  43. data/lib/database_cleaner/data_mapper/base.rb +21 -0
  44. data/lib/database_cleaner/data_mapper/transaction.rb +10 -5
  45. data/lib/database_cleaner/data_mapper/truncation.rb +52 -19
  46. data/lib/database_cleaner/generic/base.rb +23 -0
  47. data/lib/database_cleaner/generic/truncation.rb +43 -0
  48. data/lib/database_cleaner/mongo_mapper/base.rb +20 -0
  49. data/lib/database_cleaner/mongo_mapper/truncation.rb +9 -3
  50. data/lib/database_cleaner/mongoid/base.rb +20 -0
  51. data/lib/database_cleaner/mongoid/truncation.rb +9 -5
  52. data/spec/database_cleaner/active_record/base_spec.rb +130 -0
  53. data/spec/database_cleaner/active_record/truncation_spec.rb +19 -18
  54. data/spec/database_cleaner/base_spec.rb +441 -0
  55. data/spec/database_cleaner/configuration_spec.rb +255 -68
  56. data/spec/database_cleaner/couch_potato/truncation_spec.rb +4 -3
  57. data/spec/database_cleaner/data_mapper/base_spec.rb +30 -0
  58. data/spec/database_cleaner/data_mapper/transaction_spec.rb +23 -0
  59. data/spec/database_cleaner/data_mapper/truncation_spec.rb +11 -0
  60. data/spec/database_cleaner/generic/base_spec.rb +22 -0
  61. data/spec/database_cleaner/generic/truncation_spec.rb +68 -0
  62. data/spec/database_cleaner/mongo_mapper/base_spec.rb +33 -0
  63. data/spec/database_cleaner/mongo_mapper/mongo_examples.rb +8 -0
  64. data/spec/database_cleaner/mongo_mapper/truncation_spec.rb +11 -18
  65. data/spec/database_cleaner/shared_strategy_spec.rb +13 -0
  66. data/spec/rcov.opts +1 -0
  67. data/spec/spec.opts +1 -0
  68. data/spec/spec_helper.rb +10 -3
  69. metadata +76 -8
  70. data/examples/features/step_definitions/example_steps.rb +0 -8
  71. 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
- module ActiveRecord
8
- def self.available_strategies
9
- %w[truncation transaction]
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
- module DataMapper
14
- def self.available_strategies
15
- %w[truncation transaction]
18
+ def app_root=(desired_root)
19
+ @app_root = desired_root
16
20
  end
17
- end
18
-
19
21
 
20
- module MongoMapper
21
- def self.available_strategies
22
- %w[truncation]
22
+ def app_root
23
+ @app_root || Dir.pwd
23
24
  end
24
- end
25
25
 
26
- module Mongoid
27
- def self.available_strategies
28
- %w[truncation]
26
+ def connections
27
+ @connections ||= [::DatabaseCleaner::Base.new]
29
28
  end
30
- end
31
29
 
32
- module CouchPotato
33
- def self.available_strategies
34
- %w[truncation]
30
+ def strategy=(stratagem)
31
+ self.connections.each { |connect| connect.strategy = stratagem }
32
+ remove_duplicates
35
33
  end
36
- end
37
34
 
38
- class << self
39
-
40
- def create_strategy(*args)
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
- strategy.start
41
+ self.connections.each { |connection| connection.start }
70
42
  end
71
43
 
72
44
  def clean
73
- strategy.clean
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 orm_strategy(strategy)
86
- require "database_cleaner/#{orm}/#{strategy}"
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
- def orm
94
- @orm ||=begin
95
- if defined? ::ActiveRecord
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
- def orm_module
113
- case orm
114
- when 'active_record'
115
- DatabaseCleaner::ActiveRecord
116
- when 'data_mapper'
117
- DatabaseCleaner::DataMapper
118
- when 'mongo_mapper'
119
- DatabaseCleaner::MongoMapper
120
- when 'mongoid'
121
- DatabaseCleaner::Mongoid
122
- when 'couch_potato'
123
- DatabaseCleaner::CouchPotato
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
@@ -0,0 +1,7 @@
1
+ module DatabaseCleaner
2
+ module CouchPotato
3
+ def self.available_strategies
4
+ %w[truncation]
5
+ end
6
+ end
7
+ end
@@ -1,8 +1,10 @@
1
- require 'database_cleaner/truncation_base'
1
+ require 'database_cleaner/generic/truncation'
2
2
 
3
3
  module DatabaseCleaner
4
4
  module CouchPotato
5
- class Truncation < DatabaseCleaner::TruncationBase
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."
@@ -1,4 +1,3 @@
1
-
2
1
  Before do
3
2
  DatabaseCleaner.start
4
3
  end
@@ -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
- def start(repo = :default)
5
- DataMapper.repository(repo) do |r|
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(repo = :default)
13
- DataMapper.repository(repo) do |r|
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/truncation_base"
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 sql
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::DataMapper
119
- class Truncation < ::DatabaseCleaner::TruncationBase
145
+ module DatabaseCleaner
146
+ module DataMapper
147
+ class Truncation
148
+ include ::DatabaseCleaner::DataMapper::Base
149
+ include ::DatabaseCleaner::Generic::Truncation
120
150
 
121
- def clean(repository = :default)
122
- adapter = DataMapper.repository(repository).adapter
123
- adapter.disable_referential_integrity do
124
- tables_to_truncate.each do |table_name|
125
- adapter.truncate_table table_name
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
- private
161
+ private
131
162
 
132
- def tables_to_truncate(repository = :default)
133
- (@only || DataMapper.repository(repository).adapter.storage_names(repository)) - @tables_to_exclude
134
- end
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
- # overwritten
137
- def migration_storage_name
138
- 'migration_info'
139
- end
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