database_cleaner 1.7.0 → 1.8.0.beta

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTE.markdown +1 -2
  3. data/Gemfile.lock +130 -91
  4. data/History.rdoc +1 -1
  5. data/README.markdown +71 -226
  6. data/Rakefile +12 -8
  7. data/adapters/database_cleaner-active_record/lib/database_cleaner-active_record.rb +1 -0
  8. data/adapters/database_cleaner-active_record/lib/database_cleaner/active_record.rb +6 -0
  9. data/{lib → adapters/database_cleaner-active_record/lib}/database_cleaner/active_record/base.rb +13 -4
  10. data/{lib → adapters/database_cleaner-active_record/lib}/database_cleaner/active_record/deletion.rb +19 -19
  11. data/{lib → adapters/database_cleaner-active_record/lib}/database_cleaner/active_record/transaction.rb +0 -0
  12. data/{lib → adapters/database_cleaner-active_record/lib}/database_cleaner/active_record/truncation.rb +22 -19
  13. data/adapters/database_cleaner-active_record/lib/database_cleaner/active_record/version.rb +5 -0
  14. data/adapters/database_cleaner-couch_potato/lib/database_cleaner-couch_potato.rb +1 -0
  15. data/adapters/database_cleaner-couch_potato/lib/database_cleaner/couch_potato.rb +11 -0
  16. data/{lib → adapters/database_cleaner-couch_potato/lib}/database_cleaner/couch_potato/base.rb +0 -0
  17. data/{lib → adapters/database_cleaner-couch_potato/lib}/database_cleaner/couch_potato/truncation.rb +0 -0
  18. data/adapters/database_cleaner-couch_potato/lib/database_cleaner/couch_potato/version.rb +5 -0
  19. data/adapters/database_cleaner-data_mapper/lib/database_cleaner-data_mapper.rb +1 -0
  20. data/adapters/database_cleaner-data_mapper/lib/database_cleaner/data_mapper.rb +4 -0
  21. data/{lib → adapters/database_cleaner-data_mapper/lib}/database_cleaner/data_mapper/base.rb +4 -0
  22. data/{lib → adapters/database_cleaner-data_mapper/lib}/database_cleaner/data_mapper/transaction.rb +0 -0
  23. data/{lib → adapters/database_cleaner-data_mapper/lib}/database_cleaner/data_mapper/truncation.rb +4 -3
  24. data/adapters/database_cleaner-data_mapper/lib/database_cleaner/data_mapper/version.rb +5 -0
  25. data/adapters/database_cleaner-mongo/lib/database_cleaner-mongo.rb +1 -0
  26. data/adapters/database_cleaner-mongo/lib/database_cleaner/mongo.rb +10 -0
  27. data/{lib → adapters/database_cleaner-mongo/lib}/database_cleaner/mongo/base.rb +0 -0
  28. data/{lib → adapters/database_cleaner-mongo/lib}/database_cleaner/mongo/truncation.rb +0 -0
  29. data/{lib → adapters/database_cleaner-mongo/lib}/database_cleaner/mongo/truncation_mixin.rb +0 -0
  30. data/adapters/database_cleaner-mongo/lib/database_cleaner/mongo/version.rb +5 -0
  31. data/adapters/database_cleaner-mongo_mapper/lib/database_cleaner-mongo_mapper.rb +1 -0
  32. data/adapters/database_cleaner-mongo_mapper/lib/database_cleaner/mongo_mapper.rb +4 -0
  33. data/{lib → adapters/database_cleaner-mongo_mapper/lib}/database_cleaner/mongo_mapper/base.rb +4 -0
  34. data/{lib → adapters/database_cleaner-mongo_mapper/lib}/database_cleaner/mongo_mapper/truncation.rb +0 -0
  35. data/adapters/database_cleaner-mongo_mapper/lib/database_cleaner/mongo_mapper/version.rb +5 -0
  36. data/adapters/database_cleaner-mongoid/lib/database_cleaner-mongoid.rb +1 -0
  37. data/{lib → adapters/database_cleaner-mongoid/lib}/database_cleaner/mongo2/truncation_mixin.rb +0 -0
  38. data/adapters/database_cleaner-mongoid/lib/database_cleaner/mongoid.rb +10 -0
  39. data/{lib → adapters/database_cleaner-mongoid/lib}/database_cleaner/mongoid/base.rb +0 -0
  40. data/{lib → adapters/database_cleaner-mongoid/lib}/database_cleaner/mongoid/truncation.rb +0 -0
  41. data/adapters/database_cleaner-mongoid/lib/database_cleaner/mongoid/version.rb +5 -0
  42. data/adapters/database_cleaner-moped/lib/database_cleaner-moped.rb +1 -0
  43. data/adapters/database_cleaner-moped/lib/database_cleaner/moped.rb +10 -0
  44. data/{lib → adapters/database_cleaner-moped/lib}/database_cleaner/moped/base.rb +1 -1
  45. data/{lib → adapters/database_cleaner-moped/lib}/database_cleaner/moped/truncation.rb +0 -0
  46. data/{lib → adapters/database_cleaner-moped/lib}/database_cleaner/moped/truncation_base.rb +4 -0
  47. data/adapters/database_cleaner-moped/lib/database_cleaner/moped/version.rb +5 -0
  48. data/adapters/database_cleaner-neo4j/lib/database_cleaner-neo4j.rb +1 -0
  49. data/adapters/database_cleaner-neo4j/lib/database_cleaner/neo4j.rb +6 -0
  50. data/{lib → adapters/database_cleaner-neo4j/lib}/database_cleaner/neo4j/base.rb +4 -0
  51. data/{lib → adapters/database_cleaner-neo4j/lib}/database_cleaner/neo4j/deletion.rb +0 -0
  52. data/{lib → adapters/database_cleaner-neo4j/lib}/database_cleaner/neo4j/transaction.rb +0 -0
  53. data/{lib → adapters/database_cleaner-neo4j/lib}/database_cleaner/neo4j/truncation.rb +0 -0
  54. data/adapters/database_cleaner-neo4j/lib/database_cleaner/neo4j/version.rb +5 -0
  55. data/adapters/database_cleaner-ohm/lib/database_cleaner-ohm.rb +1 -0
  56. data/adapters/database_cleaner-ohm/lib/database_cleaner/ohm.rb +10 -0
  57. data/{lib → adapters/database_cleaner-ohm/lib}/database_cleaner/ohm/truncation.rb +4 -0
  58. data/adapters/database_cleaner-ohm/lib/database_cleaner/ohm/version.rb +5 -0
  59. data/adapters/database_cleaner-redis/lib/database_cleaner-redis.rb +1 -0
  60. data/adapters/database_cleaner-redis/lib/database_cleaner/redis.rb +4 -0
  61. data/{lib → adapters/database_cleaner-redis/lib}/database_cleaner/redis/base.rb +4 -0
  62. data/{lib → adapters/database_cleaner-redis/lib}/database_cleaner/redis/truncation.rb +0 -0
  63. data/adapters/database_cleaner-redis/lib/database_cleaner/redis/version.rb +5 -0
  64. data/adapters/database_cleaner-sequel/lib/database_cleaner-sequel.rb +1 -0
  65. data/adapters/database_cleaner-sequel/lib/database_cleaner/sequel.rb +6 -0
  66. data/{lib → adapters/database_cleaner-sequel/lib}/database_cleaner/sequel/base.rb +4 -0
  67. data/{lib → adapters/database_cleaner-sequel/lib}/database_cleaner/sequel/deletion.rb +0 -0
  68. data/{lib → adapters/database_cleaner-sequel/lib}/database_cleaner/sequel/transaction.rb +0 -0
  69. data/{lib → adapters/database_cleaner-sequel/lib}/database_cleaner/sequel/truncation.rb +16 -15
  70. data/adapters/database_cleaner-sequel/lib/database_cleaner/sequel/version.rb +5 -0
  71. data/lib/database_cleaner.rb +36 -1
  72. data/lib/database_cleaner/base.rb +85 -103
  73. data/lib/database_cleaner/configuration.rb +93 -83
  74. data/lib/database_cleaner/deprecation.rb +21 -0
  75. data/lib/database_cleaner/null_strategy.rb +6 -6
  76. data/lib/database_cleaner/orm_autodetector.rb +31 -0
  77. data/lib/database_cleaner/safeguard.rb +38 -3
  78. data/lib/database_cleaner/spec.rb +2 -0
  79. data/lib/database_cleaner/spec/database_helper.rb +82 -0
  80. data/lib/database_cleaner/spec/shared_examples.rb +15 -0
  81. data/lib/database_cleaner/version.rb +3 -0
  82. metadata +111 -46
  83. data/VERSION.yml +0 -4
  84. data/lib/database_cleaner/mongo2/base.rb +0 -16
@@ -1,74 +1,77 @@
1
1
  require 'database_cleaner/base'
2
+ require 'database_cleaner/deprecation'
3
+ require 'forwardable'
2
4
 
3
5
  module DatabaseCleaner
4
6
 
5
- class NoORMDetected < StandardError; end
6
- class UnknownStrategySpecified < ArgumentError; end
7
+ class NoORMDetected < StandardError; end
8
+ class UnknownStrategySpecified < ArgumentError; end
7
9
 
8
- class << self
9
- def init_cleaners
10
- @cleaners ||= {}
11
- # ghetto ordered hash.. maintains 1.8 compat and old API
12
- @connections ||= []
13
- end
14
-
15
- def [](orm,opts = {})
10
+ class Cleaners < Hash
11
+ # FIXME this method conflates creation with lookup... both a command and a query. yuck.
12
+ def [](orm, opts = {})
16
13
  raise NoORMDetected unless orm
17
- init_cleaners
18
- # TODO: deprecate
19
- # this method conflates creation with lookup. Both a command and a query. Yuck.
20
- if @cleaners.has_key? [orm, opts]
21
- @cleaners[[orm, opts]]
22
- else
23
- add_cleaner(orm, opts)
24
- end
25
- end
14
+ fetch([orm, opts]) { add_cleaner(orm, opts) }
15
+ end
26
16
 
27
- def add_cleaner(orm,opts = {})
28
- init_cleaners
29
- cleaner = DatabaseCleaner::Base.new(orm,opts)
30
- @cleaners[[orm, opts]] = cleaner
31
- @connections << cleaner
32
- cleaner
17
+ def strategy=(strategy)
18
+ add_cleaner(:autodetect) if none?
19
+ values.each { |cleaner| cleaner.strategy = strategy }
20
+ remove_duplicates
33
21
  end
34
22
 
35
- def app_root=(desired_root)
36
- @app_root = desired_root
23
+ def orm=(orm)
24
+ add_cleaner(:autodetect) if none?
25
+ values.each { |cleaner| cleaner.orm = orm }
26
+ remove_duplicates
37
27
  end
38
28
 
39
- def app_root
40
- @app_root ||= Dir.pwd
29
+ # TODO privatize the following methods in 2.0
30
+
31
+ def add_cleaner(orm, opts = {})
32
+ self[[orm, opts]] = ::DatabaseCleaner::Base.new(orm, opts)
41
33
  end
42
34
 
43
- def connections
44
- # double yuck.. can't wait to deprecate this whole class...
45
- unless defined?(@cleaners) && @cleaners
46
- autodetected = ::DatabaseCleaner::Base.new
47
- add_cleaner(autodetected.orm)
48
- end
49
- @connections
35
+ def remove_duplicates
36
+ replace(reduce(Cleaners.new) do |cleaners, (key, value)|
37
+ cleaners[key] = value unless cleaners.values.include?(value)
38
+ cleaners
39
+ end)
50
40
  end
41
+ end
51
42
 
52
- def logger=(log_source)
53
- @logger = log_source
43
+ class Configuration
44
+ def initialize
45
+ @cleaners ||= Cleaners.new
54
46
  end
55
47
 
56
- def logger
57
- return @logger if @logger
48
+ extend Forwardable
49
+ delegate [
50
+ :[],
51
+ :strategy=,
52
+ :orm=,
53
+ ] => :cleaners
54
+
55
+ attr_accessor :cleaners
58
56
 
59
- @logger = Logger.new(STDOUT)
60
- @logger.level = Logger::ERROR
61
- @logger
57
+ def app_root
58
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.app_root` is deprecated, and will be removed in database_cleaner 2.0. Use `DatabaseCleaner::ActiveRecord.config_file_location`, instead."
59
+ @app_root ||= Dir.pwd
62
60
  end
63
61
 
64
- def strategy=(stratagem)
65
- connections.each { |connect| connect.strategy = stratagem }
66
- remove_duplicates
62
+ def app_root= value
63
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.app_root=` is deprecated, and will be removed in database_cleaner 2.0. Use `DatabaseCleaner::ActiveRecord.config_file_location=`, instead."
64
+ @app_root = value
67
65
  end
68
66
 
69
- def orm=(orm)
70
- connections.each { |connect| connect.orm = orm }
71
- remove_duplicates
67
+ def logger
68
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.logger` is deprecated, and will be removed in database_cleaner 2.0 with no replacement."
69
+ @logger ||= Logger.new(STDOUT).tap { |l| l.level = Logger::ERROR }
70
+ end
71
+
72
+ def logger= value
73
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.logger=` is deprecated, and will be removed in database_cleaner 2.0 with no replacement."
74
+ @logger = value
72
75
  end
73
76
 
74
77
  def start
@@ -79,8 +82,6 @@ module DatabaseCleaner
79
82
  connections.each { |connection| connection.clean }
80
83
  end
81
84
 
82
- alias clean! clean
83
-
84
85
  def cleaning(&inner_block)
85
86
  connections.inject(inner_block) do |curr_block, connection|
86
87
  proc { connection.cleaning(&curr_block) }
@@ -91,41 +92,50 @@ module DatabaseCleaner
91
92
  connections.each { |connection| connection.clean_with(*args) }
92
93
  end
93
94
 
94
- alias clean_with! clean_with
95
+ # TODO remove the following methods in 2.0
95
96
 
96
- def remove_duplicates
97
- temp = []
98
- connections.each do |connect|
99
- temp.push connect unless temp.include? connect
97
+ def clean!
98
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.clean!` is deprecated, and will be removed in database_cleaner 2.0. Use `DatabaseCleaner.clean`, instead."
99
+ clean
100
+ end
101
+
102
+ def clean_with!(*args)
103
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.clean_with!` is deprecated, and will be removed in database_cleaner 2.0. Use `DatabaseCleaner.clean_with`, instead."
104
+ clean_with(*args)
105
+ end
106
+
107
+ def init_cleaners
108
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.init_cleaners` is deprecated, and will be removed in database_cleaner 2.0 with no replacement."
109
+ end
110
+
111
+ def connections
112
+ if called_externally?(caller)
113
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.connections` is deprecated, and will be removed in database_cleaner 2.0. Use `DatabaseCleaner.cleaners`, instead."
100
114
  end
101
- @connections = temp
102
- end
103
-
104
- def orm_module(symbol)
105
- case symbol
106
- when :active_record
107
- DatabaseCleaner::ActiveRecord
108
- when :data_mapper
109
- DatabaseCleaner::DataMapper
110
- when :mongo
111
- DatabaseCleaner::Mongo
112
- when :mongoid
113
- DatabaseCleaner::Mongoid
114
- when :mongo_mapper
115
- DatabaseCleaner::MongoMapper
116
- when :moped
117
- DatabaseCleaner::Moped
118
- when :couch_potato
119
- DatabaseCleaner::CouchPotato
120
- when :sequel
121
- DatabaseCleaner::Sequel
122
- when :ohm
123
- DatabaseCleaner::Ohm
124
- when :redis
125
- DatabaseCleaner::Redis
126
- when :neo4j
127
- DatabaseCleaner::Neo4j
115
+ add_cleaner(:autodetect) if @cleaners.none?
116
+ @cleaners.values
117
+ end
118
+
119
+ # TODO privatize the following methods in 2.0
120
+
121
+ def add_cleaner(orm, opts = {})
122
+ if called_externally?(caller)
123
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.add_cleaner` is deprecated, and will be removed in database_cleaner 2.0. Use `DatabaseCleaner.[]`, instead."
128
124
  end
125
+ @cleaners.add_cleaner(orm, opts = {})
126
+ end
127
+
128
+ def remove_duplicates
129
+ if called_externally?(caller)
130
+ DatabaseCleaner.deprecate "Calling `DatabaseCleaner.remove_duplicates` is deprecated, and will be removed in database_cleaner 2.0 with no replacement."
131
+ end
132
+ @cleaners.remove_duplicates
133
+ end
134
+
135
+ private
136
+
137
+ def called_externally?(caller)
138
+ __FILE__ != caller.first.split(":").first
129
139
  end
130
140
  end
131
141
  end
@@ -0,0 +1,21 @@
1
+ module DatabaseCleaner
2
+ def deprecate message
3
+ method = caller.first[/\d+:in `(.*)'$/, 1].to_sym
4
+ @@deprecator ||= Deprecator.new
5
+ @@deprecator.deprecate method, message
6
+ end
7
+ module_function :deprecate
8
+
9
+ class Deprecator
10
+ def initialize
11
+ @methods_already_warned = {}
12
+ end
13
+
14
+ def deprecate method, message
15
+ return if @methods_already_warned.key?(method)
16
+ $stderr.puts message
17
+ @methods_already_warned[method] = true
18
+ end
19
+ end
20
+ end
21
+
@@ -1,18 +1,18 @@
1
1
  module DatabaseCleaner
2
2
  class NullStrategy
3
- def self.start
3
+ def start
4
4
  # no-op
5
5
  end
6
6
 
7
- def self.db=(connection)
8
- # no-op
9
- end
7
+ def db=(connection)
8
+ # no-op
9
+ end
10
10
 
11
- def self.clean
11
+ def clean
12
12
  # no-op
13
13
  end
14
14
 
15
- def self.cleaning(&block)
15
+ def cleaning(&block)
16
16
  # no-op
17
17
  yield
18
18
  end
@@ -0,0 +1,31 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module DatabaseCleaner
4
+ class ORMAutodetector
5
+ ORMS = %w[ActiveRecord DataMapper MongoMapper Mongoid CouchPotato Sequel Moped Ohm Redis Neo4j]
6
+
7
+ def orm
8
+ @autodetected = true
9
+ autodetected_orm or raise no_orm_detected_error
10
+ autodetected_orm.underscore.to_sym
11
+ end
12
+
13
+ def autodetected?
14
+ !!@autodetected
15
+ end
16
+
17
+ private
18
+
19
+ def autodetected_orm
20
+ ORMS.find do |orm|
21
+ Kernel.const_get(orm) rescue next
22
+ end
23
+ end
24
+
25
+ def no_orm_detected_error
26
+ orm_list = ORMS.join(", ").sub(ORMS.last, "or #{ORMS.last}")
27
+ NoORMDetected.new("No known ORM was detected! Is #{orm_list} loaded?")
28
+ end
29
+ end
30
+ private_constant :ORMAutodetector
31
+ end
@@ -12,8 +12,32 @@ module DatabaseCleaner
12
12
  super("ENV['#{env}'] is set to production. Please refer to https://github.com/DatabaseCleaner/database_cleaner#safeguards")
13
13
  end
14
14
  end
15
+
16
+ class NotWhitelistedUrl < Error
17
+ def initialize
18
+ super("ENV['DATABASE_URL'] is set to a URL that is not on the whitelist. Please refer to https://github.com/DatabaseCleaner/database_cleaner#safeguards")
19
+ end
20
+ end
21
+ end
22
+
23
+ class WhitelistedUrl
24
+ def run
25
+ return if skip?
26
+ raise Error::NotWhitelistedUrl if database_url_not_whitelisted?
27
+ end
28
+
29
+ private
30
+
31
+ def database_url_not_whitelisted?
32
+ !DatabaseCleaner.url_whitelist.include?(ENV['DATABASE_URL'])
33
+ end
34
+
35
+ def skip?
36
+ !DatabaseCleaner.url_whitelist
37
+ end
15
38
  end
16
39
 
40
+
17
41
  class RemoteDatabaseUrl
18
42
  LOCAL = %w(localhost 127.0.0.1)
19
43
 
@@ -28,12 +52,22 @@ module DatabaseCleaner
28
52
  end
29
53
 
30
54
  def remote?(url)
31
- url && !LOCAL.any? { |str| url.include?(str) }
55
+ return false unless url
56
+
57
+ parsed = URI.parse(url)
58
+ return false if parsed.scheme == 'sqlite3:'
59
+
60
+ host = parsed.host
61
+ return false unless host
62
+ return false if LOCAL.include?(host)
63
+ return false if host.end_with? '.local'
64
+ true
32
65
  end
33
66
 
34
67
  def skip?
35
68
  ENV['DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL'] ||
36
- DatabaseCleaner.allow_remote_database_url
69
+ DatabaseCleaner.allow_remote_database_url ||
70
+ DatabaseCleaner.url_whitelist
37
71
  end
38
72
  end
39
73
 
@@ -62,7 +96,8 @@ module DatabaseCleaner
62
96
 
63
97
  CHECKS = [
64
98
  RemoteDatabaseUrl,
65
- Production
99
+ Production,
100
+ WhitelistedUrl
66
101
  ]
67
102
 
68
103
  def run
@@ -0,0 +1,2 @@
1
+ require "database_cleaner/spec/database_helper"
2
+ require "database_cleaner/spec/shared_examples"
@@ -0,0 +1,82 @@
1
+ require 'yaml'
2
+
3
+ module DatabaseCleaner
4
+ module Spec
5
+ class DatabaseHelper < Struct.new(:db)
6
+ def self.with_all_dbs &block
7
+ %w[mysql mysql2 sqlite3 postgres].map(&:to_sym).each do |db|
8
+ yield new(db)
9
+ end
10
+ end
11
+
12
+ def setup
13
+ create_db
14
+ establish_connection
15
+ load_schema
16
+ end
17
+
18
+ attr_reader :connection
19
+
20
+ def teardown
21
+ drop_db
22
+ end
23
+
24
+ private
25
+
26
+ def establish_connection(config = default_config)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ def create_db
31
+ if db == :sqlite3
32
+ # NO-OP
33
+ elsif db == :postgres
34
+ establish_connection default_config.merge('database' => 'postgres')
35
+ connection.execute "CREATE DATABASE #{default_config['database']}" rescue nil
36
+ else
37
+ establish_connection default_config.merge("database" => nil)
38
+ connection.execute "CREATE DATABASE IF NOT EXISTS #{default_config['database']}"
39
+ end
40
+ end
41
+
42
+ def load_schema
43
+ connection.execute <<-SQL
44
+ CREATE TABLE IF NOT EXISTS users (
45
+ id SERIAL PRIMARY KEY,
46
+ name INTEGER
47
+ );
48
+ SQL
49
+
50
+ connection.execute <<-SQL
51
+ CREATE TABLE IF NOT EXISTS agents (
52
+ name INTEGER
53
+ );
54
+ SQL
55
+ end
56
+
57
+ def drop_db
58
+ if db == :sqlite3
59
+ begin
60
+ File.unlink(db_config['sqlite3']['database'])
61
+ rescue Errno::ENOENT
62
+ end
63
+ elsif db == :postgres
64
+ # FIXME
65
+ connection.execute "DROP TABLE IF EXISTS users"
66
+ connection.execute "DROP TABLE IF EXISTS agents"
67
+ else
68
+ connection.execute "DROP DATABASE IF EXISTS #{default_config['database']}"
69
+ end
70
+ end
71
+
72
+ def db_config
73
+ config_path = 'spec/support/config.yml'
74
+ @db_config ||= YAML.load(IO.read(config_path))
75
+ end
76
+
77
+ def default_config
78
+ db_config[db.to_s]
79
+ end
80
+ end
81
+ end
82
+ end