activerecord-turntable 1.1.2 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.travis.yml +3 -5
  4. data/CHANGELOG.md +70 -0
  5. data/Guardfile +7 -5
  6. data/README.md +490 -0
  7. data/Rakefile +37 -22
  8. data/activerecord-turntable.gemspec +37 -34
  9. data/gemfiles/rails4_0.gemfile +6 -0
  10. data/gemfiles/rails4_1.gemfile +6 -0
  11. data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +14 -29
  12. data/lib/active_record/turntable/active_record_ext/activerecord_import_ext.rb +45 -0
  13. data/lib/active_record/turntable/active_record_ext/acts_as_archive_extension.rb +21 -0
  14. data/lib/active_record/turntable/active_record_ext/association.rb +85 -0
  15. data/lib/active_record/turntable/active_record_ext/association_preloader.rb +37 -0
  16. data/lib/active_record/turntable/active_record_ext/clever_load.rb +33 -76
  17. data/lib/active_record/turntable/active_record_ext/connection_handler_extension.rb +31 -0
  18. data/lib/active_record/turntable/active_record_ext/database_tasks.rb +81 -0
  19. data/lib/active_record/turntable/active_record_ext/fixtures.rb +54 -42
  20. data/lib/active_record/turntable/active_record_ext/locking_optimistic.rb +101 -0
  21. data/lib/active_record/turntable/active_record_ext/log_subscriber.rb +28 -46
  22. data/lib/active_record/turntable/active_record_ext/migration_proxy.rb +7 -0
  23. data/lib/active_record/turntable/active_record_ext/persistence.rb +96 -94
  24. data/lib/active_record/turntable/active_record_ext/relation.rb +31 -0
  25. data/lib/active_record/turntable/active_record_ext/schema_dumper.rb +18 -28
  26. data/lib/active_record/turntable/active_record_ext/transactions.rb +9 -3
  27. data/lib/active_record/turntable/active_record_ext.rb +26 -11
  28. data/lib/active_record/turntable/algorithm/base.rb +1 -1
  29. data/lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb +1 -1
  30. data/lib/active_record/turntable/algorithm.rb +7 -3
  31. data/lib/active_record/turntable/base.rb +67 -14
  32. data/lib/active_record/turntable/cluster.rb +46 -2
  33. data/lib/active_record/turntable/config.rb +1 -1
  34. data/lib/active_record/turntable/connection_proxy/mixable.rb +7 -29
  35. data/lib/active_record/turntable/connection_proxy.rb +61 -72
  36. data/lib/active_record/turntable/error.rb +5 -6
  37. data/lib/active_record/turntable/helpers.rb +5 -1
  38. data/lib/active_record/turntable/migration.rb +9 -49
  39. data/lib/active_record/turntable/mixer/fader/calculate_shards_sum_result.rb +13 -2
  40. data/lib/active_record/turntable/mixer/fader/select_shards_merge_result.rb +17 -6
  41. data/lib/active_record/turntable/mixer/fader/specified_shard.rb +3 -1
  42. data/lib/active_record/turntable/mixer/fader.rb +12 -10
  43. data/lib/active_record/turntable/mixer.rb +59 -29
  44. data/lib/active_record/turntable/plugin.rb +6 -0
  45. data/lib/active_record/turntable/pool_proxy.rb +12 -19
  46. data/lib/active_record/turntable/rack/query_cache.rb +20 -23
  47. data/lib/active_record/turntable/rack.rb +4 -2
  48. data/lib/active_record/turntable/railtie.rb +4 -3
  49. data/lib/active_record/turntable/railties/databases.rake +81 -122
  50. data/lib/active_record/turntable/seq_shard.rb +1 -1
  51. data/lib/active_record/turntable/sequencer/api.rb +1 -1
  52. data/lib/active_record/turntable/sequencer/barrage.rb +28 -0
  53. data/lib/active_record/turntable/sequencer.rb +27 -9
  54. data/lib/active_record/turntable/shard.rb +2 -2
  55. data/lib/active_record/turntable/sql_tree_patch.rb +1 -1
  56. data/lib/active_record/turntable/version.rb +1 -1
  57. data/lib/active_record/turntable.rb +26 -16
  58. data/lib/generators/templates/turntable.yml +9 -7
  59. data/spec/active_record/turntable/active_record_ext/association_preloader_spec.rb +78 -0
  60. data/spec/active_record/turntable/active_record_ext/association_spec.rb +72 -0
  61. data/spec/active_record/turntable/active_record_ext/clever_load_spec.rb +25 -46
  62. data/spec/active_record/turntable/active_record_ext/locking_optimistic_spec.rb +28 -0
  63. data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +46 -25
  64. data/spec/active_record/turntable/algorithm/range_algorithm_spec.rb +4 -4
  65. data/spec/active_record/turntable/algorithm/range_bsearch_algorithm_spec.rb +35 -0
  66. data/spec/active_record/turntable/algorithm_spec.rb +28 -12
  67. data/spec/active_record/turntable/base_spec.rb +1 -1
  68. data/spec/active_record/turntable/cluster_spec.rb +27 -5
  69. data/spec/active_record/turntable/config_spec.rb +2 -2
  70. data/spec/active_record/turntable/connection_proxy_spec.rb +112 -45
  71. data/spec/active_record/turntable/finder_spec.rb +24 -11
  72. data/spec/active_record/turntable/mixer_spec.rb +21 -21
  73. data/spec/active_record/turntable/rack/query_cache_spec.rb +19 -0
  74. data/spec/active_record/turntable/sequencer/api_spec.rb +38 -0
  75. data/spec/active_record/turntable/sequencer/barrage_spec.rb +22 -0
  76. data/spec/active_record/turntable/sequencer/mysql_spec.rb +22 -0
  77. data/spec/active_record/turntable/shard_spec.rb +1 -1
  78. data/spec/active_record/turntable/transaction_spec.rb +35 -0
  79. data/spec/active_record/turntable_spec.rb +4 -4
  80. data/spec/config/database.yml +24 -34
  81. data/spec/config/turntable.yml +18 -1
  82. data/spec/fabricators/turntable_fabricator.rb +0 -2
  83. data/spec/models/card.rb +3 -0
  84. data/spec/models/cards_user.rb +10 -0
  85. data/spec/models/cards_users_histories.rb +7 -0
  86. data/spec/models/events_users_history.rb +7 -0
  87. data/spec/models/user.rb +7 -0
  88. data/spec/models/user_status.rb +6 -0
  89. data/spec/spec_helper.rb +10 -4
  90. data/spec/support/matchers/be_saved_to.rb +6 -0
  91. data/spec/support/turntable_helper.rb +29 -0
  92. metadata +124 -74
  93. data/README.rdoc +0 -294
  94. data/gemfiles/rails3_0.gemfile +0 -7
  95. data/gemfiles/rails3_1.gemfile +0 -6
  96. data/gemfiles/rails3_2.gemfile +0 -6
  97. data/lib/active_record/turntable/compatible.rb +0 -19
  98. data/sample_app/.gitignore +0 -16
  99. data/sample_app/Gemfile +0 -41
  100. data/sample_app/README.rdoc +0 -261
  101. data/sample_app/Rakefile +0 -7
  102. data/sample_app/app/assets/images/rails.png +0 -0
  103. data/sample_app/app/assets/javascripts/application.js +0 -15
  104. data/sample_app/app/assets/stylesheets/application.css +0 -13
  105. data/sample_app/app/controllers/application_controller.rb +0 -3
  106. data/sample_app/app/helpers/application_helper.rb +0 -2
  107. data/sample_app/app/mailers/.gitkeep +0 -0
  108. data/sample_app/app/models/.gitkeep +0 -0
  109. data/sample_app/app/models/user.rb +0 -4
  110. data/sample_app/app/views/layouts/application.html.erb +0 -14
  111. data/sample_app/config/application.rb +0 -65
  112. data/sample_app/config/boot.rb +0 -6
  113. data/sample_app/config/database.yml +0 -70
  114. data/sample_app/config/environment.rb +0 -5
  115. data/sample_app/config/environments/development.rb +0 -37
  116. data/sample_app/config/environments/production.rb +0 -67
  117. data/sample_app/config/environments/test.rb +0 -37
  118. data/sample_app/config/initializers/backtrace_silencers.rb +0 -7
  119. data/sample_app/config/initializers/inflections.rb +0 -15
  120. data/sample_app/config/initializers/mime_types.rb +0 -5
  121. data/sample_app/config/initializers/secret_token.rb +0 -7
  122. data/sample_app/config/initializers/session_store.rb +0 -8
  123. data/sample_app/config/initializers/wrap_parameters.rb +0 -14
  124. data/sample_app/config/locales/en.yml +0 -5
  125. data/sample_app/config/routes.rb +0 -58
  126. data/sample_app/config/turntable.yml +0 -64
  127. data/sample_app/config.ru +0 -4
  128. data/sample_app/db/migrate/20120316073058_create_users.rb +0 -11
  129. data/sample_app/db/seeds.rb +0 -7
  130. data/sample_app/lib/assets/.gitkeep +0 -0
  131. data/sample_app/lib/tasks/.gitkeep +0 -0
  132. data/sample_app/log/.gitkeep +0 -0
  133. data/sample_app/public/404.html +0 -26
  134. data/sample_app/public/422.html +0 -26
  135. data/sample_app/public/500.html +0 -25
  136. data/sample_app/public/favicon.ico +0 -0
  137. data/sample_app/public/index.html +0 -241
  138. data/sample_app/public/robots.txt +0 -5
  139. data/sample_app/script/rails +0 -6
  140. data/sample_app/vendor/assets/javascripts/.gitkeep +0 -0
  141. data/sample_app/vendor/assets/stylesheets/.gitkeep +0 -0
  142. data/sample_app/vendor/plugins/.gitkeep +0 -0
  143. data/spec/test_models.rb +0 -27
  144. data/spec/turntable_helper.rb +0 -29
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::Turntable::ActiveRecordExt::Association do
4
+ before(:all) do
5
+ reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
6
+ end
7
+
8
+ before(:each) do
9
+ establish_connection_to(:test)
10
+ truncate_shard
11
+ end
12
+
13
+ let!(:user) do
14
+ user = User.new({:nickname => 'user1'})
15
+ user.id = 1
16
+ user.save
17
+ user
18
+ end
19
+
20
+ let!(:cards_users) do
21
+ 10.times.map do
22
+ CardsUser.create(user: user, card_id: 1)
23
+ end
24
+ end
25
+
26
+ let!(:cards_users_histories) do
27
+ cards_users.map do |cards_user|
28
+ CardsUsersHistory.create(cards_user: cards_user, user: user)
29
+ end
30
+ end
31
+
32
+ let!(:events_users_histories) do
33
+ cards_users.map do |cards_user|
34
+ EventsUsersHistory.create(cards_user: cards_user, user: user, events_user_id: user.id)
35
+ end
36
+ end
37
+
38
+ context "When preloads has_many association" do
39
+ before do
40
+ ActiveRecord::Base.turntable_config.instance_variable_get(:@config)[:raise_on_not_specified_shard_query] = true
41
+ end
42
+
43
+ context "associated objects has same turntable_key" do
44
+ subject { CardsUser.where(user: user).preload(:cards_users_histories).first }
45
+ it { expect { subject }.to_not raise_error }
46
+
47
+ it "its association should be loaded" do
48
+ expect(subject.association(:cards_users_histories)).to be_loaded
49
+ end
50
+
51
+ it "its has_many targets should be assigned all related object" do
52
+ expect(subject.cards_users_histories).to include(*cards_users_histories.select { |history| history.cards_user_id == subject.id} )
53
+ end
54
+ end
55
+
56
+ context "associated objects has different turntable_key" do
57
+ context "when foreign_shard_key option passed" do
58
+ subject { CardsUser.where(user: user).preload(:events_users_histories_with_foreign_shard_key).first }
59
+
60
+ it { expect { subject }.to_not raise_error }
61
+
62
+ it "its association should be loaded" do
63
+ expect(subject.association(:events_users_histories_with_foreign_shard_key)).to be_loaded
64
+ end
65
+
66
+ it "its has_many targets should be assigned all related object" do
67
+ expect(subject.events_users_histories_with_foreign_shard_key).to include(*events_users_histories.select { |history| history.cards_user_id == subject.id} )
68
+ end
69
+ end
70
+
71
+ context "when foreign_shard_key option is not passed" do
72
+ subject { CardsUser.where(user: user).preload(:events_users_histories).first }
73
+
74
+ it { expect { subject }.to raise_error }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::Turntable::ActiveRecordExt::Association do
4
+ before(:all) do
5
+ reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
6
+ end
7
+
8
+ before(:each) do
9
+ establish_connection_to(:test)
10
+ truncate_shard
11
+ end
12
+
13
+ let!(:user) do
14
+ user = User.new({:nickname => 'user1'})
15
+ user.id = 1
16
+ user.save
17
+ user
18
+ end
19
+
20
+ let!(:cards_users) do
21
+ 10.times.map do
22
+ CardsUser.create(user: user, card_id: 1)
23
+ end
24
+ end
25
+
26
+ let!(:cards_users_histories) do
27
+ cards_users.map do |cards_user|
28
+ CardsUsersHistory.create(cards_user: cards_user, user: user)
29
+ end
30
+ end
31
+
32
+ let!(:events_users_histories) do
33
+ cards_users.map do |cards_user|
34
+ EventsUsersHistory.create(cards_user: cards_user, user: user, events_user_id: user.id)
35
+ end
36
+ end
37
+
38
+ context "When a model with has_one relation" do
39
+ context "When the has_one associated object doesn't exists" do
40
+ subject { user.user_status }
41
+ it { expect { subject }.to_not raise_error }
42
+ end
43
+ end
44
+
45
+ context "With has_many association" do
46
+ before do
47
+ ActiveRecord::Base.turntable_config.instance_variable_get(:@config)[:raise_on_not_specified_shard_query] = true
48
+ end
49
+ let(:cards_user) { CardsUser.where(user: user).first }
50
+
51
+ context "associated objects has same turntable_key" do
52
+ subject { cards_user.cards_users_histories }
53
+ it { expect { subject }.to_not raise_error }
54
+ it { is_expected.to include(*cards_users_histories.select { |history| history.cards_user_id == cards_user.id }) }
55
+ end
56
+
57
+ context "associated objects has different turntable_key" do
58
+ context "when foreign_shard_key option passed" do
59
+ subject { cards_user.events_users_histories_with_foreign_shard_key }
60
+
61
+ it { expect { subject }.to_not raise_error }
62
+ it { is_expected.to include(*events_users_histories.select { |history| history.cards_user_id == cards_user.id }) }
63
+ end
64
+
65
+ context "when foreign_shard_key option is not passed" do
66
+ subject { CardsUser.where(user: user).events_users_histories }
67
+
68
+ it { expect { subject }.to raise_error }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -7,7 +7,7 @@ describe ActiveRecord::Turntable::ActiveRecordExt::CleverLoad do
7
7
  end
8
8
 
9
9
  before(:each) do
10
- establish_connection_to("test")
10
+ establish_connection_to(:test)
11
11
  truncate_shard
12
12
 
13
13
  @user1 = User.new({:nickname => 'user1'})
@@ -18,76 +18,55 @@ describe ActiveRecord::Turntable::ActiveRecordExt::CleverLoad do
18
18
  @user2.id = 2
19
19
  @user2.save
20
20
  @user2_status = @user2.create_user_status(:hp => 20, :mp => 10)
21
- ActiveRecord::Base.logger = Logger.new(STDOUT)
22
21
  end
23
22
 
24
23
  context "When a model has has_one relation" do
25
24
  context "When call clever_load!" do
26
- before(:each) do
27
- @strio = StringIO.new
28
- ActiveRecord::Base.logger = Logger.new(@strio)
29
- @users = User.clever_load!(:user_status)
30
- puts @strio.string
31
- end
32
- it "should send merged user_status select query" do
33
- @strio.string.should =~ //
34
- end
25
+ let(:users) { User.all.clever_load!(:user_status) }
26
+
27
+ context "With their associations" do
28
+ subject { users.map { |u| u.association(:user_status) } }
35
29
 
36
- it "should target loaded" do
37
- if ActiveRecord::VERSION::STRING < "3.1"
38
- @users.each do |user|
39
- user.loaded_user_status?.should be_true
40
- end
41
- else
42
- @users.each do |user|
43
- user.association(:user_status).loaded?.should be_true
44
- end
30
+ it "should be association target loaded" do
31
+ is_expected.to all(be_loaded)
45
32
  end
46
33
  end
47
34
 
48
- it "should assigned reverse relation" do
49
- pending "should be implemented"
35
+ context "With their targets" do
36
+ subject { users.map { |u| u.association(:user_status).target } }
37
+
38
+ it "should be loaded target object" do
39
+ is_expected.to all(be_instance_of(UserStatus))
40
+ end
50
41
  end
51
42
  end
52
43
  end
53
44
 
54
45
  context "When a model has belongs_to relation" do
55
46
  context "When call clever_load!" do
56
- before(:each) do
57
- @strio = StringIO.new
58
- @strio = StringIO.new
59
- ActiveRecord::Base.logger = Logger.new(@strio)
60
- @user_statuses = UserStatus.clever_load!(:user)
61
- puts @strio.string
62
- end
47
+ let(:user_statuses) { UserStatus.all.clever_load!(:user) }
63
48
 
64
- it "should send merged user_status select query" do
65
- @strio.string.should =~ //
66
- end
49
+ context "With their associations" do
50
+ subject { user_statuses.map { |us| us.association(:user) } }
67
51
 
68
- it "should target loaded" do
69
- if ActiveRecord::VERSION::STRING < "3.1"
70
- @user_statuses.each do |user_status|
71
- user_status.loaded_user?.should be_true
72
- end
73
- else
74
- @user_statuses.each do |user_status|
75
- user_status.association(:user).loaded?.should be_true
76
- end
52
+ it "should target loaded" do
53
+ is_expected.to all(be_loaded)
77
54
  end
78
55
  end
79
56
 
80
- it "should assigned reverse relation" do
81
- pending "should be implemented"
57
+ context "With their targets" do
58
+ subject { user_statuses.map { |us| us.association(:user).target } }
59
+
60
+ it "should be loaded target object" do
61
+ is_expected.to all(be_instance_of(User))
62
+ end
82
63
  end
83
64
  end
84
65
  end
85
66
 
86
67
  context "When a model has has_many relation" do
87
68
  it "should send query only 2 times." do
88
- pending "not implemented yet"
69
+ skip "not implemented yet"
89
70
  end
90
71
  end
91
-
92
-
93
72
  end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::Turntable::ActiveRecordExt::LockingOptimistic do
4
+ before(:all) do
5
+ reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
6
+ end
7
+
8
+ before(:each) do
9
+ establish_connection_to(:test)
10
+ truncate_shard
11
+ end
12
+
13
+ before do
14
+ ActiveRecord::Base.turntable_config.instance_variable_get(:@config)[:raise_on_not_specified_shard_update] = true
15
+ end
16
+
17
+ let!(:user_status) do
18
+ user_status = UserStatus.new(user_id: 1)
19
+ user_status.id = 10
20
+ user_status.save
21
+ user_status
22
+ end
23
+
24
+ describe "optimistic locking" do
25
+ subject { user_status.update_attributes(hp: 20) }
26
+ it { expect { subject }.to change(user_status, :lock_version).by(1) }
27
+ end
28
+ end
@@ -7,9 +7,15 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
7
7
  end
8
8
 
9
9
  before(:each) do
10
- establish_connection_to("test")
10
+ establish_connection_to(:test)
11
11
  truncate_shard
12
+ end
13
+
14
+ around(:each) do |example|
15
+ old = ActiveRecord::Base.logger
12
16
  ActiveRecord::Base.logger = Logger.new(STDOUT)
17
+ example.run
18
+ ActiveRecord::Base.logger = old
13
19
  end
14
20
 
15
21
  let(:user) {
@@ -37,24 +43,24 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
37
43
  expect {
38
44
  user.save!
39
45
  }.to_not raise_error
40
- strio.string.should =~ /WHERE `users`\.`id` = #{user.id}[^\s]*$/
46
+ expect(strio.string).to match(/WHERE `users`\.`id` = #{user.id}[^\s]*$/)
47
+ end
48
+
49
+ it "should be saved to target_shard" do
50
+ expect(user).to be_saved_to(user.turntable_shard)
41
51
  end
42
52
 
43
53
  it "should change updated_at when updating" do
44
54
  user.nickname = "fizzbuzz"
45
55
 
46
- lambda {
47
- user.save!
48
- }.should change(user, :updated_at)
56
+ expect { user.save! }.to change(user, :updated_at)
49
57
  end
50
58
 
51
59
  it "should not changed from normal operation when destroying" do
52
60
  strio = StringIO.new
53
61
  ActiveRecord::Base.logger = Logger.new(strio)
54
- expect {
55
- user.destroy
56
- }.to_not raise_error
57
- strio.string.should =~ /WHERE `users`\.`id` = #{user.id}[^\s]*$/
62
+ expect { user.destroy }.to_not raise_error
63
+ expect(strio.string).to match(/WHERE `users`\.`id` = #{user.id}[^\s]*$/)
58
64
  end
59
65
  end
60
66
 
@@ -74,13 +80,13 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
74
80
 
75
81
  context "on update once" do
76
82
  it "callback should be called once" do
77
- mock(user).on_update.times(1)
83
+ expect(user).to receive(:on_update).once
78
84
  user.save
79
85
  end
80
86
  end
81
87
  context "on destroy once" do
82
88
  it "callback should be called once" do
83
- mock(user).on_destroy.times(1)
89
+ expect(user).to receive(:on_destroy).once
84
90
  user.destroy
85
91
  end
86
92
  end
@@ -95,15 +101,15 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
95
101
  expect {
96
102
  user_status.save!
97
103
  }.to_not raise_error
98
- strio.string.should =~ /WHERE `user_statuses`\.`id` = #{user_status.id} AND `user_statuses`\.`user_id` = #{user_status.user_id}[^\s]*$/
104
+ expect(strio.string).to match(/`user_statuses`\.`user_id` = #{user_status.user_id}[^\s]*($|\s)/)
99
105
  end
100
106
 
101
107
  it "should change updated_at when updating" do
102
108
  user_status.hp = 20
103
109
 
104
- lambda {
110
+ expect {
105
111
  user_status.save!
106
- }.should change(user_status, :updated_at)
112
+ }.to change(user_status, :updated_at)
107
113
  end
108
114
 
109
115
  it "should send shard_key condition when destroying" do
@@ -112,11 +118,11 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
112
118
  expect {
113
119
  user_status.destroy
114
120
  }.to_not raise_error
115
- strio.string.should =~ /WHERE `user_statuses`\.`id` = #{user_status.id} AND `user_statuses`\.`user_id` = #{user_status.user_id}[^\s]*$/
121
+ expect(strio.string).to match(/`user_statuses`\.`user_id` = #{user_status.user_id}[^\s]*($|\s)/)
116
122
  end
117
123
 
118
124
  it "should warn when creating without shard_key" do
119
- pending "doesn't need to implemented soon"
125
+ skip "doesn't need to implemented soon"
120
126
  end
121
127
 
122
128
  it "should execute one query when reloading" do
@@ -124,12 +130,27 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
124
130
  strio = StringIO.new
125
131
  ActiveRecord::Base.logger = Logger.new(strio)
126
132
 
127
- expect {
128
- user_status.reload
129
- }.to_not raise_error
130
- puts strio.string
133
+ expect { user_status.reload }.to_not raise_error
134
+
135
+ expect(strio.string.split("\n").select {|stmt| stmt =~ /SELECT/ and stmt !~ /Turntable/ }).to have(1).items
136
+ end
137
+
138
+ it "should execute one query when touching" do
139
+ user; user_status
140
+ strio = StringIO.new
141
+ ActiveRecord::Base.logger = Logger.new(strio)
142
+
143
+ expect { user_status.touch }.to_not raise_error
144
+ expect(strio.string.split("\n").select {|stmt| stmt =~ /UPDATE/ and stmt !~ /Turntable/ }).to have(1).items
145
+ end
146
+
147
+ it "should execute one query when locking" do
148
+ user; user_status
149
+ strio = StringIO.new
150
+ ActiveRecord::Base.logger = Logger.new(strio)
131
151
 
132
- strio.string.split("\n").select {|stmt| stmt =~ /SELECT/ and stmt !~ /Turntable/ }.should have(1).items
152
+ expect { user_status.lock! }.to_not raise_error
153
+ expect(strio.string.split("\n").select {|stmt| stmt =~ /SELECT/ and stmt !~ /Turntable/ }).to have(1).items
133
154
  end
134
155
  end
135
156
 
@@ -141,7 +162,7 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
141
162
  expect {
142
163
  card.save!
143
164
  }.to_not raise_error
144
- strio.string.should =~ /WHERE `cards`\.`id` = #{card.id}[^\s]*$/
165
+ expect(strio.string).to match(/WHERE `cards`\.`id` = #{card.id}[^\s]*$/)
145
166
  end
146
167
 
147
168
  it "should not send shard_key condition when destroying" do
@@ -150,14 +171,14 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
150
171
  expect {
151
172
  card.destroy
152
173
  }.to_not raise_error
153
- strio.string.should =~ /WHERE `cards`\.`id` = #{card.id}[^\s]*$/
174
+ expect(strio.string).to match(/WHERE `cards`\.`id` = #{card.id}[^\s]*$/)
154
175
  end
155
176
  end
156
177
 
157
178
  context "When call reload" do
158
179
  subject { user_status.reload }
159
- it { should be_instance_of(UserStatus)}
160
- it { should == user_status }
180
+ it { is_expected.to be_instance_of(UserStatus)}
181
+ it { is_expected.to eq(user_status) }
161
182
  end
162
183
 
163
184
  end
@@ -12,22 +12,22 @@ describe ActiveRecord::Turntable::Algorithm::RangeAlgorithm do
12
12
 
13
13
  context "#calculate with 1" do
14
14
  subject { @alg.calculate(1) }
15
- it { should == ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection] }
15
+ it { is_expected.to eq(ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection]) }
16
16
  end
17
17
 
18
18
  context "#calculate with 19999" do
19
19
  subject { @alg.calculate(19999) }
20
- it { should == ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection] }
20
+ it { is_expected.to eq(ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection]) }
21
21
  end
22
22
 
23
23
  context "#calculate with 20000" do
24
24
  subject { @alg.calculate(20000) }
25
- it { should == ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][1][:connection] }
25
+ it { is_expected.to eq(ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][1][:connection]) }
26
26
  end
27
27
 
28
28
  context "#calculate with 10000000" do
29
29
  it "raises ActiveRecord::Turntable::CannotSpecifyShardError" do
30
- lambda { @alg.calculate(10000000) }.should raise_error(ActiveRecord::Turntable::CannotSpecifyShardError)
30
+ expect { @alg.calculate(10000000) }.to raise_error(ActiveRecord::Turntable::CannotSpecifyShardError)
31
31
  end
32
32
  end
33
33
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::Turntable::Algorithm::RangeBsearchAlgorithm do
4
+ before(:all) do
5
+ reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
6
+ end
7
+
8
+ context "When initialized" do
9
+ before do
10
+ @alg = ActiveRecord::Turntable::Algorithm::RangeBsearchAlgorithm.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster])
11
+ end
12
+
13
+ context "#calculate with 1" do
14
+ subject { @alg.calculate(1) }
15
+ it { is_expected.to eq(ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection]) }
16
+ end
17
+
18
+ context "#calculate with 19999" do
19
+ subject { @alg.calculate(19999) }
20
+ it { is_expected.to eq(ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection]) }
21
+ end
22
+
23
+ context "#calculate with 20000" do
24
+ subject { @alg.calculate(20000) }
25
+ it { is_expected.to eq(ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][1][:connection]) }
26
+ end
27
+
28
+ context "#calculate with 10000000" do
29
+ it "raises ActiveRecord::Turntable::CannotSpecifyShardError" do
30
+ expect { @alg.calculate(10000000) }.to raise_error(ActiveRecord::Turntable::CannotSpecifyShardError)
31
+ end
32
+ end
33
+ end
34
+
35
+ end
@@ -9,29 +9,37 @@ describe ActiveRecord::Turntable::Algorithm do
9
9
  let(:algorithm) { ActiveRecord::Turntable::Algorithm::RangeBsearchAlgorithm.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
10
10
  context "#calculate" do
11
11
  it "called with 1 returns user_shard_1" do
12
- algorithm.calculate(1).should == "user_shard_1"
12
+ expect(algorithm.calculate(1)).to eq("user_shard_1")
13
+ end
14
+
15
+ it "called with 19999 returns user_shard_1" do
16
+ expect(algorithm.calculate(19999)).to eq("user_shard_1")
17
+ end
18
+
19
+ it "called with 20000 returns user_shard_2" do
20
+ expect(algorithm.calculate(20000)).to eq("user_shard_2")
13
21
  end
14
22
 
15
23
  it "called with 100000 returns user_shard_3" do
16
- algorithm.calculate(100000).should == "user_shard_3"
24
+ expect(algorithm.calculate(100000)).to eq("user_shard_3")
17
25
  end
18
26
  end
19
27
 
20
28
  context "#calculate_used_shards_with_weight" do
21
29
  it "called with 10 returns 1 item" do
22
- algorithm.calculate_used_shards_with_weight(10).should have(1).items
30
+ expect(algorithm.calculate_used_shards_with_weight(10)).to have(1).items
23
31
  end
24
32
 
25
33
  it "called with 10 returns {\"user_shard_1\" => 10}" do
26
- algorithm.calculate_used_shards_with_weight(10).should == {"user_shard_1" => 10}
34
+ expect(algorithm.calculate_used_shards_with_weight(10)).to eq({"user_shard_1" => 10})
27
35
  end
28
36
 
29
37
  it "called with 65000 returns 2 items" do
30
- algorithm.calculate_used_shards_with_weight(65000).should have(2).items
38
+ expect(algorithm.calculate_used_shards_with_weight(65000)).to have(2).items
31
39
  end
32
40
 
33
41
  it "called with 65000 returns {\"user_shard_1\" => 39999, \"user_shard_2\" => 25001}" do
34
- algorithm.calculate_used_shards_with_weight(65000).should == {"user_shard_1" => 39999, "user_shard_2" => 25001}
42
+ expect(algorithm.calculate_used_shards_with_weight(65000)).to eq({"user_shard_1" => 39999, "user_shard_2" => 25001})
35
43
  end
36
44
  end
37
45
  end
@@ -40,29 +48,37 @@ describe ActiveRecord::Turntable::Algorithm do
40
48
  let(:algorithm) { ActiveRecord::Turntable::Algorithm::RangeAlgorithm.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
41
49
  context "#calculate" do
42
50
  it "called with 1 returns user_shard_1" do
43
- algorithm.calculate(1).should == "user_shard_1"
51
+ expect(algorithm.calculate(1)).to eq("user_shard_1")
52
+ end
53
+
54
+ it "called with 19999 returns user_shard_1" do
55
+ expect(algorithm.calculate(19999)).to eq("user_shard_1")
56
+ end
57
+
58
+ it "called with 20000 returns user_shard_2" do
59
+ expect(algorithm.calculate(20000)).to eq("user_shard_2")
44
60
  end
45
61
 
46
62
  it "called with 100000 returns user_shard_3" do
47
- algorithm.calculate(100000).should == "user_shard_3"
63
+ expect(algorithm.calculate(100000)).to eq("user_shard_3")
48
64
  end
49
65
  end
50
66
 
51
67
  context "#calculate_used_shards_with_weight" do
52
68
  it "called with 10 returns 1 item" do
53
- algorithm.calculate_used_shards_with_weight(10).should have(1).items
69
+ expect(algorithm.calculate_used_shards_with_weight(10)).to have(1).items
54
70
  end
55
71
 
56
72
  it "called with 10 returns {\"user_shard_1\" => 10}" do
57
- algorithm.calculate_used_shards_with_weight(10).should == {"user_shard_1" => 10}
73
+ expect(algorithm.calculate_used_shards_with_weight(10)).to eq({"user_shard_1" => 10})
58
74
  end
59
75
 
60
76
  it "called with 65000 returns 2 items" do
61
- algorithm.calculate_used_shards_with_weight(65000).should have(2).items
77
+ expect(algorithm.calculate_used_shards_with_weight(65000)).to have(2).items
62
78
  end
63
79
 
64
80
  it "called with 65000 returns {\"user_shard_1\" => 39999, \"user_shard_2\" => 25001}" do
65
- algorithm.calculate_used_shards_with_weight(65000).should == {"user_shard_1" => 39999, "user_shard_2" => 25001}
81
+ expect(algorithm.calculate_used_shards_with_weight(65000)).to eq({"user_shard_1" => 39999, "user_shard_2" => 25001})
66
82
  end
67
83
  end
68
84
  end
@@ -7,7 +7,7 @@ describe ActiveRecord::Turntable::Base do
7
7
 
8
8
  context "When installed to ActiveRecord::Base" do
9
9
  it "ActiveRecord::Base respond_to 'turntable'" do
10
- ActiveRecord::Base.should respond_to(:turntable)
10
+ expect(ActiveRecord::Base).to respond_to(:turntable)
11
11
  end
12
12
  end
13
13
  end
@@ -5,14 +5,36 @@ describe ActiveRecord::Turntable::Cluster do
5
5
  reload_turntable!(File.join(File.dirname(__FILE__), "../../config/turntable.yml"))
6
6
  end
7
7
 
8
+ before do
9
+ establish_connection_to(:test)
10
+ truncate_shard
11
+ end
12
+ let(:cluster_config) { ActiveRecord::Base.turntable_config[:clusters][:user_cluster] }
13
+ let(:cluster) { ActiveRecord::Turntable::Cluster.new(User, cluster_config) }
14
+ let(:in_range_shard_key_value) { cluster_config[:shards].last[:less_than] - 1 }
15
+ let(:out_of_range_shard_key_value) { cluster_config[:shards].last[:less_than] }
16
+
8
17
  context "When initialized" do
9
- before do
10
- establish_connection_to("test")
11
- truncate_shard
12
- end
18
+ subject { cluster }
13
19
 
14
- subject { ActiveRecord::Turntable::Cluster.new(User, ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
15
20
  its(:klass) { should == User }
16
21
  its(:shards) { should have(3).items }
17
22
  end
23
+
24
+ describe "#shard_for" do
25
+ subject { cluster.shard_for(value) }
26
+
27
+ context "with argument in shard range value" do
28
+ let(:value) { in_range_shard_key_value }
29
+ let(:expected_shard_name) { cluster_config[:shards].last[:connection] }
30
+
31
+ it { is_expected.to be_instance_of(ActiveRecord::Turntable::Shard) }
32
+ its(:name) { is_expected.to eq expected_shard_name }
33
+ end
34
+
35
+ context "with argument out of shard range value" do
36
+ let(:value) { out_of_range_shard_key_value }
37
+ it { expect { subject }.to raise_error(ActiveRecord::Turntable::CannotSpecifyShardError) }
38
+ end
39
+ end
18
40
  end
@@ -8,10 +8,10 @@ describe ActiveRecord::Turntable::Config do
8
8
  subject { ActiveRecord::Turntable::Config }
9
9
 
10
10
  it "has config hash" do
11
- subject.instance.instance_variable_get(:@config).should be_an_kind_of(Hash)
11
+ expect(subject.instance.instance_variable_get(:@config)).to be_an_kind_of(Hash)
12
12
  end
13
13
 
14
14
  it "has cluster setting" do
15
- subject[:clusters][:user_cluster].should be_instance_of(ActiveSupport::HashWithIndifferentAccess)
15
+ expect(subject[:clusters][:user_cluster]).to be_instance_of(ActiveSupport::HashWithIndifferentAccess)
16
16
  end
17
17
  end