database_cleaner 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,20 @@
1
1
  == 0.7.x (in git)
2
2
 
3
+ == 0.7.1 2012-01-15
4
+
5
+ === New Features
6
+
7
+ * Support for Rails 3.2. (David Demaree)
8
+
9
+ === Bugfixes
10
+
11
+ * Truncation resets the id count on SQLite. (Jordan Hollinger)
12
+ * AR delete strategy now disables referential integrity. (Ben Mabey)
13
+ * Fixes Postgres adapter for JRuby. (Dmytrii Nagirniak, Uģis Ozols)
14
+ * Documenation fixes. (Josh Rendek, Joshua Flanagan)
15
+ * Fixes bad error message when no database is specified for AR. (issue #72, Ben Mabey)
16
+
17
+
3
18
  == 0.7.0 2011-11-12
4
19
 
5
20
  === New Features
@@ -5,7 +5,7 @@ The original use case was to ensure a clean state during tests. Each strategy
5
5
  is a small amount of code but is code that is usually needed in any ruby app
6
6
  that is testing with a database.
7
7
 
8
- ActiveRecord, DataMapper, MongoMapper, Mongoid, and CouchPotato are supported.
8
+ ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, and CouchPotato are supported.
9
9
 
10
10
  Here is an overview of the strategies supported for each library:
11
11
 
@@ -14,15 +14,16 @@ Here is an overview of the strategies supported for each library:
14
14
  | DataMapper | Yes | **Yes** | No |
15
15
  | CouchPotato | **Yes** | No | No |
16
16
  | MongoMapper | **Yes** | No | No |
17
- | Mongoid | **Yes** | No | No |
17
+ | Sequel | **Yes** | Yes | No |
18
18
 
19
19
  (Default strategy for each library is denoted in bold)
20
20
 
21
- The ActiveRecord @:deletion@ strategy is only useful for when the @:truncation@ strategy causes
22
- locks (as reported by some Oracle DB users). The @:truncation@ strategy is the preferred option
23
- since it is much faster.
21
+ The ActiveRecord @:deletion@ strategy is useful for when the @:truncation@ strategy causes
22
+ locks (as reported by some Oracle DB users). The @:deletion@ option has been reported to
23
+ be faster than @:truncation@ in some cases as well. In general, the best approach is to use
24
+ @:transaction@ since it is the fastest.
24
25
 
25
- Database Cleaner also includes a @null@ strategy (that does no cleaning at all) which can be used
26
+ Database Cleaner also includes a @null@ strategy (that does no cleaning at all) which can be used
26
27
  with any ORM library. You can also explicitly use it by setting your strategy to @nil@.
27
28
 
28
29
  h2. How to use
@@ -70,7 +71,7 @@ strategy the remaining time. To accomplish this you can say:
70
71
  # then make the DatabaseCleaner.start and DatabaseCleaner.clean calls appropriately
71
72
  </pre>
72
73
 
73
- Example usage with RSpec:
74
+ h3. RSpec Example
74
75
 
75
76
  <pre>
76
77
  RSpec.configure do |config|
@@ -91,7 +92,38 @@ RSpec.configure do |config|
91
92
  end
92
93
  </pre>
93
94
 
94
- For use in Cucumber please see the section below.
95
+ h3. Cucumber Example
96
+
97
+ Add this to your features/support/env.rb file:
98
+
99
+ <pre>
100
+ begin
101
+ require 'database_cleaner'
102
+ require 'database_cleaner/cucumber'
103
+ DatabaseCleaner.strategy = :truncation
104
+ rescue NameError
105
+ raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
106
+ end
107
+ </pre>
108
+
109
+ A good idea is to create the before and after hooks to use the DatabaseCleaner.start and DatabaseCleaner.clean methods.
110
+
111
+ Inside features/support/hooks.rb:
112
+
113
+ <pre>
114
+ Before do
115
+ DatabaseCleaner.start
116
+ end
117
+
118
+ After do |scenario|
119
+ DatabaseCleaner.clean
120
+ end
121
+ </pre>
122
+
123
+ This should cover the basics of tear down between scenarios and keeping your database clean.
124
+ For more examples see the section "Why?"
125
+
126
+ h2. Common Errors
95
127
 
96
128
  In rare cases DatabaseCleaner will encounter errors that it will log. By default it uses STDOUT set to the ERROR level but you can configure this to use whatever Logger you desire. Here's an example of using the Rails.logger in env.rb:
97
129
 
@@ -114,7 +146,7 @@ Sometimes you need to use multiple ORMs in your application. You can use Databas
114
146
  #How to specify particular orms
115
147
  DatabaseCleaner[:active_record].strategy = :transaction
116
148
  DatabaseCleaner[:mongo_mapper].strategy = :truncation
117
-
149
+
118
150
  #How to specify particular connections
119
151
  DatabaseCleaner[:active_record,{:connection => :two}]
120
152
  </pre>
@@ -130,6 +162,7 @@ Configuration options
130
162
  | Mongo Mapper | DatabaseCleaner[:mongo_mapper] | Multiple connections not yet supported |
131
163
  | Mongoid | DatabaseCleaner[:mongoid] | Multiple connections not yet supported |
132
164
  | Couch Potato | DatabaseCleaner[:couch_potato] | Multiple connections not yet supported |
165
+ | Sequel | DatabaseCleaner[:sequel] | ? |
133
166
 
134
167
  h2. Why?
135
168
 
@@ -2,4 +2,4 @@
2
2
  :major: 0
3
3
  :build:
4
4
  :minor: 7
5
- :patch: 0
5
+ :patch: 1
@@ -43,7 +43,7 @@ module DatabaseCleaner
43
43
  end
44
44
 
45
45
  def connection_klass
46
- return ::ActiveRecord::Base if connection_hash.nil?
46
+ return ::ActiveRecord::Base unless connection_hash
47
47
  klass = create_connection_klass
48
48
  klass.send :establish_connection, connection_hash
49
49
  klass
@@ -54,8 +54,10 @@ module DatabaseCleaner::ActiveRecord
54
54
 
55
55
  def clean
56
56
  connection = connection_klass.connection
57
- tables_to_truncate(connection).each do |table_name|
58
- connection.delete_table table_name
57
+ connection.disable_referential_integrity do
58
+ tables_to_truncate(connection).each do |table_name|
59
+ connection.delete_table table_name
60
+ end
59
61
  end
60
62
  end
61
63
 
@@ -14,6 +14,8 @@ module DatabaseCleaner::ActiveRecord
14
14
 
15
15
 
16
16
  def clean
17
+ return unless connection_klass.connection.open_transactions > 0
18
+
17
19
  connection_klass.connection.rollback_db_transaction
18
20
 
19
21
  if connection_klass.connection.respond_to?(:decrement_open_transactions)
@@ -29,8 +29,17 @@ module ActiveRecord
29
29
  end
30
30
  end
31
31
 
32
- MYSQL_ADAPTER_PARENT = USE_ARJDBC_WORKAROUND ? JdbcAdapter : AbstractAdapter
32
+ # ActiveRecord 3.1 support
33
+ if defined?(AbstractMysqlAdapter)
34
+ MYSQL_ADAPTER_PARENT = USE_ARJDBC_WORKAROUND ? JdbcAdapter : AbstractMysqlAdapter
35
+ MYSQL2_ADAPTER_PARENT = AbstractMysqlAdapter
36
+ else
37
+ MYSQL_ADAPTER_PARENT = USE_ARJDBC_WORKAROUND ? JdbcAdapter : AbstractAdapter
38
+ MYSQL2_ADAPTER_PARENT = AbstractAdapter
39
+ end
40
+
33
41
  SQLITE_ADAPTER_PARENT = USE_ARJDBC_WORKAROUND ? JdbcAdapter : SQLiteAdapter
42
+ POSTGRE_ADAPTER_PARENT = USE_ARJDBC_WORKAROUND ? JdbcAdapter : AbstractAdapter
34
43
 
35
44
  class MysqlAdapter < MYSQL_ADAPTER_PARENT
36
45
  def truncate_table(table_name)
@@ -38,7 +47,7 @@ module ActiveRecord
38
47
  end
39
48
  end
40
49
 
41
- class Mysql2Adapter < AbstractAdapter
50
+ class Mysql2Adapter < MYSQL2_ADAPTER_PARENT
42
51
  def truncate_table(table_name)
43
52
  execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
44
53
  end
@@ -53,6 +62,7 @@ module ActiveRecord
53
62
  class SQLite3Adapter < SQLITE_ADAPTER_PARENT
54
63
  def delete_table(table_name)
55
64
  execute("DELETE FROM #{quote_table_name(table_name)};")
65
+ execute("DELETE FROM sqlite_sequence where name = '#{table_name}';")
56
66
  end
57
67
  alias truncate_table delete_table
58
68
  end
@@ -67,7 +77,7 @@ module ActiveRecord
67
77
  end
68
78
  end
69
79
 
70
- class PostgreSQLAdapter < AbstractAdapter
80
+ class PostgreSQLAdapter < POSTGRE_ADAPTER_PARENT
71
81
 
72
82
  def db_version
73
83
  @db_version ||= postgresql_version
@@ -138,3 +148,4 @@ module DatabaseCleaner::ActiveRecord
138
148
  end
139
149
 
140
150
 
151
+
@@ -80,7 +80,7 @@ module DatabaseCleaner
80
80
  alias clean! clean
81
81
 
82
82
  def auto_detected?
83
- return true unless @autodetected.nil?
83
+ !!@autodetected
84
84
  end
85
85
 
86
86
  #TODO make strategies directly comparable
@@ -7,7 +7,7 @@ module DatabaseCleaner
7
7
 
8
8
  class << self
9
9
  def [](orm,opts = {})
10
- raise NoORMDetected if orm.nil?
10
+ raise NoORMDetected unless orm
11
11
  @connections ||= []
12
12
  cleaner = DatabaseCleaner::Base.new(orm,opts)
13
13
  connections.push cleaner
@@ -3,9 +3,8 @@ require 'database_cleaner/data_mapper/base'
3
3
  module DatabaseCleaner::DataMapper
4
4
  class Transaction
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?
6
+
7
+ def start(repository = self.db)
9
8
  ::DataMapper.repository(repository) do |r|
10
9
  transaction = DataMapper::Transaction.new(r)
11
10
  transaction.begin
@@ -13,8 +12,7 @@ module DatabaseCleaner::DataMapper
13
12
  end
14
13
  end
15
14
 
16
- def clean(repository = nil)
17
- repository = self.db if repository.nil?
15
+ def clean(repository = self.db)
18
16
  ::DataMapper.repository(repository) do |r|
19
17
  adapter = r.adapter
20
18
  while adapter.current_transaction
@@ -53,6 +53,7 @@ module DataMapper
53
53
 
54
54
  def truncate_table(table_name)
55
55
  execute("DELETE FROM #{quote_name(table_name)};")
56
+ execute("DELETE FROM sqlite_sequence where name = '#{table_name}';")
56
57
  end
57
58
 
58
59
  # this is a no-op copied from activerecord
@@ -79,6 +80,7 @@ module DataMapper
79
80
 
80
81
  def truncate_table(table_name)
81
82
  execute("DELETE FROM #{quote_name(table_name)};")
83
+ execute("DELETE FROM sqlite_sequence where name = '#{table_name}';")
82
84
  end
83
85
 
84
86
  # this is a no-op copied from activerecord
@@ -107,7 +109,7 @@ module DataMapper
107
109
  end
108
110
 
109
111
  def truncate_table(table_name)
110
- execute("TRUNCATE TABLE #{quote_name(table_name)} CASCADE;")
112
+ execute("TRUNCATE TABLE #{quote_name(table_name)} RESTART IDENTITY CASCADE;")
111
113
  end
112
114
 
113
115
  # FIXME
@@ -148,8 +150,7 @@ module DatabaseCleaner
148
150
  include ::DatabaseCleaner::DataMapper::Base
149
151
  include ::DatabaseCleaner::Generic::Truncation
150
152
 
151
- def clean(repository = nil)
152
- repository = self.db if repository.nil?
153
+ def clean(repository = self.db)
153
154
  adapter = ::DataMapper.repository(repository).adapter
154
155
  adapter.disable_referential_integrity do
155
156
  tables_to_truncate(repository).each do |table_name|
@@ -160,8 +161,7 @@ module DatabaseCleaner
160
161
 
161
162
  private
162
163
 
163
- def tables_to_truncate(repository = nil)
164
- repository = self.db if repository.nil?
164
+ def tables_to_truncate(repository = self.db)
165
165
  (@only || ::DataMapper.repository(repository).adapter.storage_names(repository)) - @tables_to_exclude
166
166
  end
167
167
 
@@ -1,42 +1,36 @@
1
1
  module DatabaseCleaner
2
2
  module Generic
3
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] || []).dup
19
- @tables_to_exclude << migration_storage_name unless migration_storage_name.nil?
4
+ def initialize(opts={})
5
+ if !opts.empty? && !(opts.keys - [:only, :except]).empty?
6
+ raise ArgumentError, "The only valid options are :only and :except. You specified #{opts.keys.join(',')}."
20
7
  end
21
-
22
- def start
23
- #included for compatability reasons, do nothing if you don't need to
8
+ if opts.has_key?(:only) && opts.has_key?(:except)
9
+ raise ArgumentError, "You may only specify either :only or :except. Doing both doesn't really make sense does it?"
24
10
  end
25
11
 
26
- def clean
27
- raise NotImplementedError
28
- end
12
+ @only = opts[:only]
13
+ @tables_to_exclude = (opts[:except] || []).dup
14
+ @tables_to_exclude << migration_storage_name if migration_storage_name
15
+ end
29
16
 
30
- private
31
- def tables_to_truncate
32
- raise NotImplementedError
33
- end
17
+ def start
18
+ #included for compatability reasons, do nothing if you don't need to
19
+ end
20
+
21
+ def clean
22
+ raise NotImplementedError
23
+ end
24
+
25
+ private
26
+ def tables_to_truncate
27
+ raise NotImplementedError
28
+ end
34
29
 
35
- # overwrite in subclasses
36
- # default implementation given because migration storage need not be present
37
- def migration_storage_name
38
- nil
39
- end
30
+ # overwrite in subclasses
31
+ # default implementation given because migration storage need not be present
32
+ def migration_storage_name
33
+ nil
40
34
  end
41
35
  end
42
36
  end
@@ -34,7 +34,6 @@ module DatabaseCleaner
34
34
  it_should_behave_like "a generic strategy"
35
35
 
36
36
  describe "db" do
37
- it { should respond_to(:db=) }
38
37
 
39
38
  it "should store my desired db" do
40
39
  subject.stub(:load_config)
@@ -55,9 +54,8 @@ module DatabaseCleaner
55
54
 
56
55
  describe "load_config" do
57
56
 
58
- it { should respond_to(:load_config) }
59
-
60
57
  before do
58
+ subject.db = :my_db
61
59
  yaml = <<-Y
62
60
  my_db:
63
61
  database: <%= "ONE".downcase %>
@@ -81,7 +79,6 @@ my_db:
81
79
  end
82
80
 
83
81
  it "should store the relevant config in connection_hash" do
84
- subject.should_receive(:db).and_return(:my_db)
85
82
  subject.load_config
86
83
  subject.connection_hash.should == {"database" => "one"}
87
84
  end
@@ -91,11 +88,17 @@ my_db:
91
88
  subject.load_config
92
89
  subject.connection_hash.should be_blank
93
90
  end
91
+
92
+ it "skips the file when the db is set to :default" do
93
+ # to avoid https://github.com/bmabey/database_cleaner/issues/72
94
+ subject.db = :default
95
+ YAML.should_not_receive(:load)
96
+ subject.load_config
97
+ end
98
+
94
99
  end
95
100
 
96
101
  describe "connection_hash" do
97
- it { should respond_to(:connection_hash) }
98
- it { should respond_to(:connection_hash=) }
99
102
  it "should store connection_hash" do
100
103
  subject.connection_hash = { :key => "value" }
101
104
  subject.connection_hash.should == { :key => "value" }
@@ -38,12 +38,17 @@ module DatabaseCleaner
38
38
 
39
39
  describe "#clean" do
40
40
  it "should start a transaction" do
41
+ connection.should_receive(:open_transactions).and_return(1)
42
+
41
43
  connection.stub!(:decrement_open_transactions)
42
44
 
43
45
  connection.should_receive(:rollback_db_transaction)
44
46
  Transaction.new.clean
45
47
  end
48
+
46
49
  it "should decrement open transactions if possible" do
50
+ connection.should_receive(:open_transactions).and_return(1)
51
+
47
52
  connection.stub!(:respond_to?).with(:decrement_open_transactions).and_return(true)
48
53
  connection.stub!(:rollback_db_transaction)
49
54
 
@@ -51,7 +56,14 @@ module DatabaseCleaner
51
56
  Transaction.new.clean
52
57
  end
53
58
 
59
+ it "should not try to decrement or rollback if open_transactions is 0 for whatever reason" do
60
+ connection.should_receive(:open_transactions).and_return(0)
61
+
62
+ Transaction.new.clean
63
+ end
64
+
54
65
  it "should decrement connection via ActiveRecord::Base if connection won't" do
66
+ connection.should_receive(:open_transactions).and_return(1)
55
67
  connection.stub!(:respond_to?).with(:decrement_open_transactions).and_return(false)
56
68
  connection.stub!(:rollback_db_transaction)
57
69
 
@@ -24,6 +24,7 @@ module DatabaseCleaner
24
24
  end
25
25
 
26
26
  it "should default to :default" do
27
+ pending "I figure out how to use Sequel and write some real tests for it..."
27
28
  subject.db.should == :default
28
29
  end
29
30
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: database_cleaner
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 1
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 0
10
- version: 0.7.0
9
+ - 1
10
+ version: 0.7.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ben Mabey
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-12 00:00:00 Z
18
+ date: 2012-01-15 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: Strategies for cleaning databases. Can be used to ensure a clean state for testing.