active_record_shards 2.7.3 → 2.7.4
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/lib/active_record_shards/migration.rb +23 -12
- data/lib/active_record_shards/model.rb +5 -11
- data/test/configuration_parser_test.rb +20 -20
- data/test/connection_switching_test.rb +107 -98
- data/test/helper.rb +6 -8
- data/test/migrator_test.rb +20 -5
- metadata +4 -3
@@ -39,21 +39,32 @@ module ActiveRecord
|
|
39
39
|
|
40
40
|
# list of pending migrations is any migrations that haven't run on all shards.
|
41
41
|
def pending_migrations
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
pending, missing = self.class.shard_status(migrations.map(&:version))
|
43
|
+
pending = pending.values.flatten
|
44
|
+
migrations.select { |m| pending.include?(m.version) }
|
45
|
+
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
# public
|
48
|
+
# list of pending and missing versions per shard
|
49
|
+
# [{1 => [1234567]}, {1 => [2345678]}]
|
50
|
+
def self.shard_status(versions)
|
51
|
+
pending = {}
|
52
|
+
missing = {}
|
53
|
+
|
54
|
+
collect = lambda do |shard|
|
55
|
+
migrated = get_all_versions
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
|
57
|
+
p = versions - migrated
|
58
|
+
pending[shard] = p if p.any?
|
59
|
+
|
60
|
+
m = migrated - versions
|
61
|
+
missing[shard] = m if m.any?
|
56
62
|
end
|
63
|
+
|
64
|
+
ActiveRecord::Base.on_shard(nil) { collect.call(nil) }
|
65
|
+
ActiveRecord::Base.on_all_shards { |shard| collect.call(shard) }
|
66
|
+
|
67
|
+
return pending, missing
|
57
68
|
end
|
58
69
|
end
|
59
70
|
end
|
@@ -32,8 +32,7 @@ module ActiveRecordShards
|
|
32
32
|
end
|
33
33
|
|
34
34
|
module InstanceMethods
|
35
|
-
def
|
36
|
-
after_initialize_without_slave if respond_to?(:after_initialize_without_slave)
|
35
|
+
def initialize_shard_and_slave
|
37
36
|
@from_slave = !!self.class.current_shard_selection.options[:slave]
|
38
37
|
@from_shard = self.class.current_shard_selection.options[:shard]
|
39
38
|
end
|
@@ -49,16 +48,11 @@ module ActiveRecordShards
|
|
49
48
|
|
50
49
|
def self.extended(base)
|
51
50
|
base.send(:include, InstanceMethods)
|
52
|
-
|
53
|
-
|
54
|
-
base.
|
55
|
-
else
|
56
|
-
if base.method_defined?(:after_initialize)
|
57
|
-
base.alias_method_chain :after_initialize, :slave
|
58
|
-
else
|
59
|
-
base.send(:alias_method, :after_initialize, :after_initialize_with_slave)
|
60
|
-
end
|
51
|
+
if ActiveRecord::VERSION::MAJOR == 2 && !base.method_defined?(:after_initialize)
|
52
|
+
# trick rails 2 into running callbacks
|
53
|
+
base.send(:define_method, :after_initialize){}
|
61
54
|
end
|
55
|
+
base.after_initialize :initialize_shard_and_slave
|
62
56
|
end
|
63
57
|
end
|
64
58
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
describe ActiveRecordShards::ConfigurationParser do
|
4
|
+
describe "exploding the database.yml" do
|
5
|
+
before do
|
6
6
|
@exploded_conf = ActiveRecordShards::ConfigurationParser.explode(YAML::load(IO.read(File.dirname(__FILE__) + '/database_parse_test.yml')))
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
describe "main slave" do
|
10
|
+
before { @conf = @exploded_conf['test_slave'] }
|
11
|
+
it "be exploded" do
|
12
12
|
@conf["shard_names"] = @conf["shard_names"].to_set
|
13
13
|
assert_equal({
|
14
14
|
"adapter" => "mysql",
|
@@ -23,10 +23,10 @@ class ConfigurationParserTest < ActiveSupport::TestCase
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
describe "shard a" do
|
27
|
+
describe "master" do
|
28
|
+
before { @conf = @exploded_conf['test_shard_a'] }
|
29
|
+
it "be exploded" do
|
30
30
|
@conf["shard_names"] = @conf["shard_names"].to_set
|
31
31
|
assert_equal({
|
32
32
|
"adapter" => "mysql",
|
@@ -41,9 +41,9 @@ class ConfigurationParserTest < ActiveSupport::TestCase
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
describe "slave" do
|
45
|
+
before { @conf = @exploded_conf['test_shard_a_slave'] }
|
46
|
+
it "be exploded" do
|
47
47
|
@conf["shard_names"] = @conf["shard_names"].to_set
|
48
48
|
assert_equal({
|
49
49
|
"adapter" => "mysql",
|
@@ -59,10 +59,10 @@ class ConfigurationParserTest < ActiveSupport::TestCase
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
describe "shard b" do
|
63
|
+
describe "master" do
|
64
|
+
before { @conf = @exploded_conf['test_shard_b'] }
|
65
|
+
it "be exploded" do
|
66
66
|
@conf["shard_names"] = @conf["shard_names"].to_set
|
67
67
|
assert_equal({
|
68
68
|
"adapter" => "mysql",
|
@@ -77,9 +77,9 @@ class ConfigurationParserTest < ActiveSupport::TestCase
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
describe "slave" do
|
81
|
+
before { @conf = @exploded_conf['test_shard_b_slave'] }
|
82
|
+
it "be exploded" do
|
83
83
|
@conf["shard_names"] = @conf["shard_names"].to_set
|
84
84
|
assert_equal({
|
85
85
|
"adapter" => "mysql",
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
describe "connection switching" do
|
4
|
+
i_suck_and_my_tests_are_order_dependent!
|
5
|
+
|
6
|
+
describe "shard switching" do
|
7
|
+
it "only switch connection on sharded models" do
|
6
8
|
assert_using_database('ars_test', Ticket)
|
7
9
|
assert_using_database('ars_test', Account)
|
8
10
|
|
@@ -12,7 +14,7 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
|
-
|
17
|
+
it "switch to shard and back" do
|
16
18
|
assert_using_database('ars_test')
|
17
19
|
ActiveRecord::Base.on_slave { assert_using_database('ars_test_slave') }
|
18
20
|
|
@@ -33,22 +35,22 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
33
35
|
ActiveRecord::Base.on_slave { assert_using_database('ars_test_slave') }
|
34
36
|
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
describe "on_first_shard" do
|
39
|
+
it "use the first shard" do
|
38
40
|
ActiveRecord::Base.on_first_shard {
|
39
41
|
assert_using_database('ars_test_shard0')
|
40
42
|
}
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
+
describe "on_all_shards" do
|
47
|
+
before do
|
46
48
|
@shard_0_master = ActiveRecord::Base.on_shard(0) {ActiveRecord::Base.connection}
|
47
49
|
@shard_1_master = ActiveRecord::Base.on_shard(1) {ActiveRecord::Base.connection}
|
48
|
-
|
50
|
+
refute_equal(@shard_0_master.select_value("SELECT DATABASE()"), @shard_1_master.select_value("SELECT DATABASE()"))
|
49
51
|
end
|
50
52
|
|
51
|
-
|
53
|
+
it "execute the block on all shard masters" do
|
52
54
|
result = ActiveRecord::Base.on_all_shards do |shard|
|
53
55
|
[ActiveRecord::Base.connection.select_value("SELECT DATABASE()"), shard]
|
54
56
|
end
|
@@ -56,15 +58,15 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
56
58
|
database_shards = result.map(&:last)
|
57
59
|
|
58
60
|
assert_equal(2, database_names.size)
|
59
|
-
|
60
|
-
|
61
|
+
assert_includes(database_names, @shard_0_master.select_value("SELECT DATABASE()"))
|
62
|
+
assert_includes(database_names, @shard_1_master.select_value("SELECT DATABASE()"))
|
61
63
|
|
62
64
|
assert_equal(2, database_shards.size)
|
63
|
-
|
64
|
-
|
65
|
+
assert_includes(database_shards, "0")
|
66
|
+
assert_includes(database_shards, "1")
|
65
67
|
end
|
66
68
|
|
67
|
-
|
69
|
+
it "execute the block unsharded" do
|
68
70
|
ActiveRecord::Base.expects(:supports_sharding?).returns false
|
69
71
|
result = ActiveRecord::Base.on_all_shards do |shard|
|
70
72
|
[ActiveRecord::Base.connection.select_value("SELECT DATABASE()"), shard]
|
@@ -74,33 +76,33 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
-
|
79
|
+
describe "default shard selection" do
|
80
|
+
describe "of nil" do
|
81
|
+
before do
|
80
82
|
ActiveRecord::Base.default_shard = nil
|
81
83
|
end
|
82
84
|
|
83
|
-
|
85
|
+
it "use unsharded db for sharded models" do
|
84
86
|
assert_using_database('ars_test', Ticket)
|
85
87
|
assert_using_database('ars_test', Account)
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
|
-
|
90
|
-
|
91
|
+
describe "value" do
|
92
|
+
before do
|
91
93
|
ActiveRecord::Base.default_shard = 0
|
92
94
|
end
|
93
95
|
|
94
|
-
|
96
|
+
after do
|
95
97
|
ActiveRecord::Base.default_shard = nil
|
96
98
|
end
|
97
99
|
|
98
|
-
|
100
|
+
it "use default shard db for sharded models" do
|
99
101
|
assert_using_database('ars_test_shard0', Ticket)
|
100
102
|
assert_using_database('ars_test', Account)
|
101
103
|
end
|
102
104
|
|
103
|
-
|
105
|
+
it "still be able to switch to shard nil" do
|
104
106
|
ActiveRecord::Base.on_shard(nil) do
|
105
107
|
assert_using_database('ars_test', Ticket)
|
106
108
|
assert_using_database('ars_test', Account)
|
@@ -109,44 +111,44 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
+
describe "ActiveRecord::Base.columns" do
|
115
|
+
before do
|
114
116
|
ActiveRecord::Base.default_shard = nil
|
115
117
|
end
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
+
describe "for unsharded models" do
|
120
|
+
it "use the non-sharded connection" do
|
119
121
|
assert_using_database('ars_test', Account)
|
120
122
|
Account.connection.execute("alter table accounts add column foo int")
|
121
123
|
|
122
124
|
assert Account.column_names.include?('foo')
|
123
125
|
end
|
124
126
|
|
125
|
-
|
127
|
+
after do
|
126
128
|
ActiveRecord::Base.connection.execute("alter table accounts drop column foo")
|
127
129
|
Account.reset_column_information
|
128
130
|
end
|
129
131
|
end
|
130
132
|
|
131
|
-
|
132
|
-
|
133
|
+
describe "for sharded models" do
|
134
|
+
before do
|
133
135
|
ActiveRecord::Base.on_first_shard do
|
134
136
|
ActiveRecord::Base.connection.execute("alter table tickets add column foo int")
|
135
137
|
end
|
136
138
|
end
|
137
139
|
|
138
|
-
|
140
|
+
after do
|
139
141
|
ActiveRecord::Base.on_first_shard do
|
140
142
|
ActiveRecord::Base.connection.execute("alter table tickets drop column foo")
|
141
143
|
Ticket.reset_column_information
|
142
144
|
end
|
143
145
|
end
|
144
146
|
|
145
|
-
|
147
|
+
it "get colmns from the first shard" do
|
146
148
|
assert Ticket.column_names.include?('foo')
|
147
149
|
end
|
148
150
|
|
149
|
-
|
151
|
+
it "have correct from_shard" do
|
150
152
|
ActiveRecord::Base.on_all_shards do |shard|
|
151
153
|
assert_equal shard, Ticket.new.from_shard
|
152
154
|
end
|
@@ -154,13 +156,13 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
154
156
|
end
|
155
157
|
end
|
156
158
|
|
157
|
-
|
158
|
-
|
159
|
+
describe "ActiveRecord::Base.table_exists?" do
|
160
|
+
before do
|
159
161
|
ActiveRecord::Base.default_shard = nil
|
160
162
|
end
|
161
163
|
|
162
|
-
|
163
|
-
|
164
|
+
describe "for unsharded models" do
|
165
|
+
it "use the unsharded connection" do
|
164
166
|
class UnshardedModel < ActiveRecord::Base
|
165
167
|
not_sharded
|
166
168
|
end
|
@@ -173,8 +175,8 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
173
175
|
end
|
174
176
|
end
|
175
177
|
|
176
|
-
|
177
|
-
|
178
|
+
describe "for sharded models" do
|
179
|
+
it "try the first shard" do
|
178
180
|
class ShardedModel < ActiveRecord::Base
|
179
181
|
end
|
180
182
|
|
@@ -187,31 +189,31 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
187
189
|
end
|
188
190
|
end
|
189
191
|
|
190
|
-
|
191
|
-
|
192
|
+
describe "in an unsharded environment" do
|
193
|
+
before do
|
192
194
|
silence_warnings { ::RAILS_ENV = 'test2' }
|
193
195
|
ActiveRecord::Base.establish_connection(::RAILS_ENV)
|
194
196
|
assert_using_database('ars_test2', Ticket)
|
195
197
|
end
|
196
198
|
|
197
|
-
|
199
|
+
after do
|
198
200
|
silence_warnings { ::RAILS_ENV = 'test' }
|
199
201
|
ActiveRecord::Base.establish_connection(::RAILS_ENV)
|
200
202
|
assert_using_database('ars_test', Ticket)
|
201
203
|
end
|
202
204
|
|
203
205
|
if ActiveRecord::VERSION::MAJOR >= 3
|
204
|
-
|
206
|
+
it "be able to find by column" do
|
205
207
|
Account.where(:name => "peter").to_sql # does not blow up
|
206
208
|
end
|
207
209
|
|
208
|
-
|
210
|
+
it "have correct engine" do
|
209
211
|
assert_equal Account, Account.arel_engine
|
210
212
|
end
|
211
213
|
end
|
212
214
|
|
213
|
-
|
214
|
-
|
215
|
+
describe "shard switching" do
|
216
|
+
it "just stay on the main db" do
|
215
217
|
assert_using_database('ars_test2', Ticket)
|
216
218
|
assert_using_database('ars_test2', Account)
|
217
219
|
|
@@ -222,31 +224,31 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
222
224
|
end
|
223
225
|
end
|
224
226
|
|
225
|
-
|
226
|
-
|
227
|
+
describe "on_all_shards" do
|
228
|
+
before do
|
227
229
|
@database_names = []
|
228
230
|
ActiveRecord::Base.on_all_shards do
|
229
231
|
@database_names << ActiveRecord::Base.connection.select_value("SELECT DATABASE()")
|
230
232
|
end
|
231
233
|
end
|
232
234
|
|
233
|
-
|
235
|
+
it "execute the block on all shard masters" do
|
234
236
|
@database_names
|
235
237
|
assert_equal([ActiveRecord::Base.connection.select_value("SELECT DATABASE()")], @database_names)
|
236
238
|
end
|
237
239
|
end
|
238
240
|
end
|
239
241
|
|
240
|
-
|
241
|
-
|
242
|
+
describe "slave driving" do
|
243
|
+
describe "without slave configuration" do
|
242
244
|
|
243
|
-
|
245
|
+
before do
|
244
246
|
ActiveRecord::Base.configurations.delete('test_slave')
|
245
247
|
ActiveRecord::Base.connection_handler.connection_pools.clear
|
246
248
|
ActiveRecord::Base.establish_connection('test')
|
247
249
|
end
|
248
250
|
|
249
|
-
|
251
|
+
it "default to the master database" do
|
250
252
|
Account.create!
|
251
253
|
|
252
254
|
ActiveRecord::Base.on_slave { assert_using_master_db }
|
@@ -254,7 +256,7 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
254
256
|
Ticket.on_slave { assert_using_master_db }
|
255
257
|
end
|
256
258
|
|
257
|
-
|
259
|
+
it "successfully execute queries" do
|
258
260
|
Account.create!
|
259
261
|
assert_using_master_db
|
260
262
|
|
@@ -264,9 +266,9 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
264
266
|
|
265
267
|
end
|
266
268
|
|
267
|
-
|
269
|
+
describe "with slave configuration" do
|
268
270
|
|
269
|
-
|
271
|
+
it "successfully execute queries" do
|
270
272
|
assert_using_master_db
|
271
273
|
Account.create!
|
272
274
|
|
@@ -274,7 +276,7 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
274
276
|
assert_equal(0, ActiveRecord::Base.on_slave { Account.count })
|
275
277
|
end
|
276
278
|
|
277
|
-
|
279
|
+
it "support global on_slave blocks" do
|
278
280
|
assert_using_master_db
|
279
281
|
assert_using_master_db
|
280
282
|
|
@@ -287,7 +289,7 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
287
289
|
assert_using_master_db
|
288
290
|
end
|
289
291
|
|
290
|
-
|
292
|
+
it "support conditional methods" do
|
291
293
|
assert_using_master_db
|
292
294
|
|
293
295
|
Account.on_slave_if(true) do
|
@@ -309,8 +311,8 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
309
311
|
end
|
310
312
|
end
|
311
313
|
|
312
|
-
|
313
|
-
|
314
|
+
describe "a model loaded with the slave" do
|
315
|
+
before do
|
314
316
|
Account.connection.execute("INSERT INTO accounts (id, name, created_at, updated_at) VALUES(1000, 'master_name', '2009-12-04 20:18:48', '2009-12-04 20:18:48')")
|
315
317
|
assert(Account.find(1000))
|
316
318
|
assert_equal('master_name', Account.find(1000).name)
|
@@ -322,23 +324,23 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
322
324
|
assert_equal('slave_name', @model.name)
|
323
325
|
end
|
324
326
|
|
325
|
-
|
327
|
+
it "read from master on reload" do
|
326
328
|
@model.reload
|
327
329
|
assert_equal('master_name', @model.name)
|
328
330
|
end
|
329
331
|
|
330
|
-
|
332
|
+
it "be marked as read only" do
|
331
333
|
assert(@model.readonly?)
|
332
334
|
end
|
333
335
|
|
334
|
-
|
336
|
+
it "be marked as comming from the slave" do
|
335
337
|
assert(@model.from_slave?)
|
336
338
|
end
|
337
339
|
end
|
338
340
|
|
339
|
-
|
341
|
+
describe "a inherited model without cached columns hash" do
|
340
342
|
# before columns -> with_scope -> type-condition -> columns == loop
|
341
|
-
|
343
|
+
it "not loop when on slave by default" do
|
342
344
|
Person.on_slave_by_default = true
|
343
345
|
assert User.on_slave_by_default?
|
344
346
|
assert User.finder_needs_type_condition?
|
@@ -348,8 +350,8 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
348
350
|
end
|
349
351
|
end
|
350
352
|
|
351
|
-
|
352
|
-
|
353
|
+
describe "a model loaded with the master" do
|
354
|
+
before do
|
353
355
|
Account.connection.execute("INSERT INTO accounts (id, name, created_at, updated_at) VALUES(1000, 'master_name', '2009-12-04 20:18:48', '2009-12-04 20:18:48')")
|
354
356
|
@model = Account.first
|
355
357
|
assert(@model)
|
@@ -358,57 +360,57 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
358
360
|
|
359
361
|
# TODO mocha raises stack level too deep on ActiveRecord 3.2+
|
360
362
|
if ActiveRecord::VERSION::STRING < "3.2.0"
|
361
|
-
|
363
|
+
it "not unnecessary call with_scope" do
|
362
364
|
Account.expects(:with_scope).never
|
363
365
|
Account.on_master.first
|
364
366
|
end
|
365
367
|
end
|
366
368
|
|
367
|
-
|
369
|
+
it "not unset readonly" do
|
368
370
|
@model = Account.on_master.scoped(:readonly => true).first
|
369
371
|
assert(@model.readonly?)
|
370
372
|
end
|
371
373
|
|
372
|
-
|
374
|
+
it "not be marked as read only" do
|
373
375
|
assert(!@model.readonly?)
|
374
376
|
end
|
375
377
|
|
376
|
-
|
378
|
+
it "not be marked as comming from the slave" do
|
377
379
|
assert(!@model.from_slave?)
|
378
380
|
end
|
379
381
|
end
|
380
382
|
|
381
383
|
# TODO: make all this stuff rails 3 compatible.
|
382
|
-
|
383
|
-
|
384
|
+
describe "with finds routed to the slave by default" do
|
385
|
+
before do
|
384
386
|
Account.on_slave_by_default = true
|
385
387
|
Account.connection.execute("INSERT INTO accounts (id, name, created_at, updated_at) VALUES(1000, 'master_name', '2009-12-04 20:18:48', '2009-12-04 20:18:48')")
|
386
388
|
Account.on_slave.connection.execute("INSERT INTO accounts (id, name, created_at, updated_at) VALUES(1000, 'slave_name', '2009-12-04 20:18:48', '2009-12-04 20:18:48')")
|
387
389
|
Account.on_slave.connection.execute("INSERT INTO accounts (id, name, created_at, updated_at) VALUES(1001, 'slave_name2', '2009-12-04 20:18:48', '2009-12-04 20:18:48')")
|
388
390
|
end
|
389
391
|
|
390
|
-
|
392
|
+
it "find() by default on the slave" do
|
391
393
|
account = Account.find(1000)
|
392
394
|
assert_equal 'slave_name', account.name
|
393
395
|
end
|
394
396
|
|
395
|
-
|
397
|
+
it "count() by default on the slave" do
|
396
398
|
count = Account.all.size
|
397
399
|
assert_equal 2, count
|
398
400
|
end
|
399
401
|
|
400
|
-
|
402
|
+
it "reload() on the master" do
|
401
403
|
account = Account.find(1000)
|
402
404
|
assert_equal 'master_name', account.reload.name
|
403
405
|
end
|
404
406
|
|
405
|
-
|
407
|
+
it "do exists? on the slave" do
|
406
408
|
if Account.respond_to?(:exists?)
|
407
409
|
assert Account.exists?(1001)
|
408
410
|
end
|
409
411
|
end
|
410
412
|
|
411
|
-
|
413
|
+
it "count associations on the slave" do
|
412
414
|
AccountThing.on_slave_by_default = true
|
413
415
|
Account.on_slave.connection.execute("INSERT INTO account_things (id, account_id) VALUES(123123, 1000)")
|
414
416
|
Account.on_slave.connection.execute("INSERT INTO account_things (id, account_id) VALUES(123124, 1000)")
|
@@ -416,57 +418,64 @@ class ConnectionSwitchingTest < ActiveSupport::TestCase
|
|
416
418
|
AccountThing.on_slave_by_default = false
|
417
419
|
end
|
418
420
|
|
419
|
-
|
421
|
+
it "Allow override using on_master" do
|
420
422
|
model = Account.on_master.find(1000)
|
421
423
|
assert_equal "master_name", model.name
|
422
424
|
end
|
423
425
|
|
424
|
-
|
426
|
+
it "not override on_master with on_slave" do
|
425
427
|
model = Account.on_master { Account.on_slave.find(1000) }
|
426
428
|
assert_equal "master_name", model.name
|
427
429
|
end
|
428
430
|
|
429
|
-
|
431
|
+
it "override on_slave with on_master" do
|
430
432
|
model = Account.on_slave { Account.on_master.find(1000) }
|
431
433
|
assert_equal "master_name", model.name
|
432
434
|
end
|
433
435
|
|
434
|
-
|
436
|
+
it "propogate the default_slave setting to inherited classes" do
|
435
437
|
assert AccountInherited.on_slave_by_default?
|
436
438
|
end
|
437
439
|
|
438
|
-
|
440
|
+
after do
|
439
441
|
Account.on_slave_by_default = false
|
440
442
|
end
|
441
443
|
end
|
442
444
|
end
|
443
445
|
|
444
|
-
|
445
|
-
|
446
|
+
describe "slave proxy" do
|
447
|
+
it "successfully execute queries" do
|
446
448
|
assert_using_master_db
|
447
449
|
Account.create!
|
448
450
|
|
449
|
-
|
451
|
+
refute_equal Account.count, Account.on_slave.count
|
450
452
|
end
|
451
453
|
|
452
|
-
|
453
|
-
|
454
|
-
|
454
|
+
it "work on association collections" do
|
455
|
+
begin
|
456
|
+
assert_using_master_db
|
457
|
+
account = Account.create!
|
455
458
|
|
456
|
-
|
459
|
+
account.tickets.create! :title => 'master ticket'
|
457
460
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
+
Ticket.on_slave {
|
462
|
+
account.tickets.create! :title => 'slave ticket'
|
463
|
+
}
|
461
464
|
|
462
|
-
|
463
|
-
|
465
|
+
assert_equal "master ticket", account.tickets.first.title
|
466
|
+
assert_equal "slave ticket", account.tickets.on_slave.first.title
|
467
|
+
rescue Exception
|
468
|
+
retried ||= 0
|
469
|
+
retried += 1
|
470
|
+
puts "Failed in #{__LINE__}##{retried}"
|
471
|
+
retry if retried < 3
|
472
|
+
end
|
464
473
|
end
|
465
474
|
end
|
466
475
|
end
|
467
476
|
|
468
|
-
|
469
|
-
|
477
|
+
describe "alternative connections" do
|
478
|
+
it "not interfere with other connections" do
|
470
479
|
assert_using_database('ars_test', Account)
|
471
480
|
assert_using_database('ars_test', Ticket)
|
472
481
|
assert_using_database('ars_test_alternative', Email)
|
data/test/helper.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require '
|
2
|
-
require
|
3
|
-
require 'test/unit'
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.require
|
4
3
|
|
5
|
-
|
6
|
-
|
4
|
+
require 'minitest/autorun'
|
5
|
+
MiniTest::Reporters.use! MiniTest::Reporters::DefaultReporter.new
|
7
6
|
|
8
7
|
if defined?(Debugger)
|
9
8
|
::Debugger.start
|
@@ -14,7 +13,6 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
14
13
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
14
|
require 'active_record_shards'
|
16
15
|
require 'logger'
|
17
|
-
require 'shoulda'
|
18
16
|
|
19
17
|
RAILS_ENV = "test"
|
20
18
|
|
@@ -34,7 +32,7 @@ init_schema
|
|
34
32
|
require 'models'
|
35
33
|
|
36
34
|
require 'active_support/test_case'
|
37
|
-
class
|
35
|
+
class Minitest::Spec
|
38
36
|
def clear_databases
|
39
37
|
ActiveRecord::Base.configurations.each do |name, conf|
|
40
38
|
ActiveRecord::Base.establish_connection(name)
|
@@ -43,7 +41,7 @@ class ActiveSupport::TestCase
|
|
43
41
|
end
|
44
42
|
ActiveRecord::Base.establish_connection(RAILS_ENV)
|
45
43
|
end
|
46
|
-
|
44
|
+
before { clear_databases }
|
47
45
|
|
48
46
|
def assert_using_master_db
|
49
47
|
assert_using_database('ars_test')
|
data/test/migrator_test.rb
CHANGED
@@ -10,12 +10,12 @@ class CowardlyMigration < ActiveRecord::Migration
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
describe ActiveRecord::Migrator do
|
14
|
+
before do
|
15
15
|
init_schema
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
it "migrates" do
|
19
19
|
migration_path = File.join(File.dirname(__FILE__), "/migrations")
|
20
20
|
ActiveRecord::Migrator.migrate(migration_path)
|
21
21
|
ActiveRecord::Base.on_all_shards do
|
@@ -57,7 +57,7 @@ class MigratorTest < ActiveSupport::TestCase
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
|
60
|
+
it "does not migrate bad migrations" do
|
61
61
|
migration_path = File.join(File.dirname(__FILE__), "/cowardly_migration")
|
62
62
|
exception = nil
|
63
63
|
begin
|
@@ -68,7 +68,7 @@ class MigratorTest < ActiveSupport::TestCase
|
|
68
68
|
assert e
|
69
69
|
end
|
70
70
|
|
71
|
-
|
71
|
+
it "fails with failing migrations" do
|
72
72
|
# like, if you have to break a migration in the middle somewhere.
|
73
73
|
migration_path = File.join(File.dirname(__FILE__), "/failure_migration")
|
74
74
|
|
@@ -87,7 +87,22 @@ class MigratorTest < ActiveSupport::TestCase
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
describe "#shard_status" do
|
91
|
+
it "shows nothing if everything is ok" do
|
92
|
+
ActiveRecord::Migrator.shard_status([1]).must_equal([{}, {}])
|
93
|
+
end
|
94
|
+
|
95
|
+
it "shows missing migrations" do
|
96
|
+
ActiveRecord::Migrator.shard_status([]).must_equal([{}, {nil => [1], "0" => [1], "1" => [1]}])
|
97
|
+
end
|
98
|
+
|
99
|
+
it "shows pending migrations" do
|
100
|
+
ActiveRecord::Migrator.shard_status([1, 2]).must_equal([{nil => [2], "0" => [2], "1" => [2]}, {}])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
90
104
|
private
|
105
|
+
|
91
106
|
def failure_migration_pending?(migration_path)
|
92
107
|
ActiveRecord::Migrator.new(:up, migration_path).pending_migrations.detect { |f| f.name == "FailureMigration" }
|
93
108
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_shards
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-
|
14
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activerecord
|
@@ -89,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
89
|
version: '0'
|
90
90
|
requirements: []
|
91
91
|
rubyforge_project:
|
92
|
-
rubygems_version: 1.8.
|
92
|
+
rubygems_version: 1.8.25
|
93
93
|
signing_key:
|
94
94
|
specification_version: 3
|
95
95
|
summary: Simple database switching for ActiveRecord.
|
@@ -106,3 +106,4 @@ test_files:
|
|
106
106
|
- test/migrator_test.rb
|
107
107
|
- test/models.rb
|
108
108
|
- test/schema.rb
|
109
|
+
has_rdoc:
|