database_cleaner 0.5.2 → 0.6.0.rc.1

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