fresh_connection 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/Appraisals +17 -0
  4. data/README.md +72 -8
  5. data/Rakefile +5 -0
  6. data/fresh_connection.gemspec +6 -1
  7. data/gemfiles/rails3.gemfile +9 -0
  8. data/gemfiles/rails40.gemfile +9 -0
  9. data/gemfiles/rails41.gemfile +9 -0
  10. data/lib/fresh_connection.rb +39 -9
  11. data/lib/fresh_connection/abstract_connection_manager.rb +4 -1
  12. data/lib/fresh_connection/access_control.rb +56 -0
  13. data/lib/fresh_connection/connection_manager.rb +2 -2
  14. data/lib/fresh_connection/extend/ar_base.rb +47 -0
  15. data/lib/fresh_connection/extend/ar_relation.rb +44 -0
  16. data/lib/fresh_connection/extend/connection_handler.rb +16 -0
  17. data/lib/fresh_connection/extend/mysql2_adapter.rb +46 -0
  18. data/lib/fresh_connection/initializer.rb +35 -0
  19. data/lib/fresh_connection/rack/connection_management.rb +1 -1
  20. data/lib/fresh_connection/railtie.rb +7 -4
  21. data/lib/fresh_connection/slave_connection.rb +29 -65
  22. data/lib/fresh_connection/slave_connection_handler.rb +43 -0
  23. data/lib/fresh_connection/version.rb +1 -1
  24. data/log/.gitkeep +0 -0
  25. data/spec/database.yml +14 -0
  26. data/spec/db_schema.sql +291 -0
  27. data/spec/prepare.rb +33 -0
  28. data/spec/spec_helper.rb +8 -0
  29. data/spec/support/active_record_logger.rb +3 -0
  30. data/spec/unit/access_control_spec.rb +63 -0
  31. data/spec/unit/ar_base_spec.rb +42 -0
  32. data/spec/unit/fresh_connection_spec.rb +106 -0
  33. data/spec/unit/recovery_spec.rb +39 -0
  34. metadata +154 -81
  35. data/lib/fresh_connection/active_record/abstract_adapter.rb +0 -35
  36. data/lib/fresh_connection/active_record/mysql2_adapter.rb +0 -14
  37. data/lib/fresh_connection/active_record/relation.rb +0 -33
data/spec/prepare.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'yaml'
2
+
3
+ system("mysql -uroot < spec/db_schema.sql")
4
+
5
+ module ActiveRecord
6
+ class Base
7
+ self.configurations = YAML.load_file(File.join(File.dirname(__FILE__), "database.yml"))
8
+ establish_connection
9
+ establish_fresh_connection :slave1
10
+ end
11
+ end
12
+
13
+ class Parent < ActiveRecord::Base
14
+ self.abstract_class = true
15
+ end
16
+
17
+ class Slave2 < ActiveRecord::Base
18
+ self.abstract_class = true
19
+ establish_fresh_connection :slave2
20
+ end
21
+
22
+ class User < ActiveRecord::Base
23
+ has_one :address
24
+ has_many :tels
25
+ end
26
+
27
+ class Address < ActiveRecord::Base
28
+ belongs_to :user
29
+ end
30
+
31
+ class Tel < Slave2
32
+ belongs_to :user
33
+ end
@@ -0,0 +1,8 @@
1
+ ENV["RAILS_ENV"]="test"
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'fresh_connection'
4
+
5
+ FreshConnection::Initializer.extend_active_record
6
+ require File.join(File.dirname(__FILE__), "prepare.rb")
7
+
8
+ Dir[File.join(File.dirname(__FILE__), "/support/**/*.rb")].each {|f| require f}
@@ -0,0 +1,3 @@
1
+ require 'logger'
2
+
3
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), '../../log/sql.log'))
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe FreshConnection::AccessControl do
4
+ before(:each) do
5
+ @ac = FreshConnection::AccessControl
6
+ end
7
+
8
+ context ".access" do
9
+ it "persisted first state(slave)" do
10
+ ret = []
11
+ @ac.access(true) do
12
+ @ac.access(true) do
13
+ ret << @ac.slave_access?
14
+ @ac.access(false) do
15
+ ret << @ac.slave_access?
16
+ end
17
+ end
18
+ end
19
+
20
+ expect(ret).to be_all{|item| item}
21
+ end
22
+
23
+ it "persisted first state(master)" do
24
+ ret = []
25
+ @ac.access(false) do
26
+ @ac.access(true) do
27
+ ret << @ac.slave_access?
28
+ @ac.access(false) do
29
+ ret << @ac.slave_access?
30
+ end
31
+ end
32
+ end
33
+
34
+ expect(ret).to_not be_all{|item| item}
35
+ end
36
+
37
+ it "outside is always master" do
38
+ ret = []
39
+ ret << @ac.slave_access?
40
+ @ac.access(true){}
41
+ ret << @ac.slave_access?
42
+
43
+ expect(ret).to_not be_all{|item| item}
44
+ end
45
+ end
46
+
47
+ context ".force_master_access" do
48
+ it "forced master state" do
49
+ @ac.access(true) do
50
+ @ac.force_master_access do
51
+ expect(@ac.slave_access?).to be_false
52
+ end
53
+ end
54
+ end
55
+
56
+ it "not effect outside" do
57
+ @ac.access(true) do
58
+ @ac.force_master_access {}
59
+ expect(@ac.slave_access?).to be_true
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::Base do
4
+ context ".slave_connection" do
5
+ it "return Mysql2Adapter object" do
6
+ expect(User.slave_connection).to be_a(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
7
+ end
8
+ end
9
+
10
+ context ".slave_group" do
11
+ class Tel2 < Slave2
12
+ self.table_name = :tel
13
+ end
14
+
15
+ it "equal group_name of establish_fresh_connection" do
16
+ expect(User.slave_group).to eq("slave1")
17
+ expect(Tel.slave_group).to eq("slave2")
18
+ end
19
+
20
+ it "equal 'slave' when not specific group_name" do
21
+ Tel2.establish_fresh_connection
22
+ expect(Tel2.slave_group).to eq("slave")
23
+ end
24
+ end
25
+
26
+ context ".master_db_only?" do
27
+ class User2 < Parent
28
+ self.table_name = :users
29
+ end
30
+
31
+ it "childrend of master_db_only class is master_db_only" do
32
+ expect(User2.master_db_only?).to be_false
33
+ Parent.master_db_only!
34
+ expect(User2.master_db_only?).to be_true
35
+ end
36
+
37
+ it "not effect other class" do
38
+ Parent.master_db_only!
39
+ expect(Address.master_db_only?).to be_false
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ describe FreshConnection do
4
+ before(:each) do
5
+ @user = User.first
6
+ end
7
+
8
+ context "access to slave" do
9
+ it "select from User is to access to slave1" do
10
+ data = [
11
+ @user.name,
12
+ Address.first.user.name,
13
+ Tel.first.user.name,
14
+ ]
15
+
16
+ expect(data).to be_all{|n| n.include?("slave1")}
17
+ end
18
+
19
+ it "select from Address is to access to slave1" do
20
+ data = [
21
+ Address.first.prefecture,
22
+ @user.address.prefecture
23
+ ]
24
+
25
+ expect(data).to be_all{|n| n.include?("slave1")}
26
+ end
27
+
28
+ it "select from Address is to access to slave2" do
29
+ data = [
30
+ Tel.first.number,
31
+ @user.tels.first.number
32
+ ]
33
+
34
+ expect(data).to be_all{|n| n.include?("slave2")}
35
+ end
36
+
37
+ it "select with join is to access to slave1" do
38
+ name = User.joins(:address).where("addresses.user_id = 1").first.name
39
+ expect(name).to be_include("slave1")
40
+ end
41
+ end
42
+
43
+ context "access to master" do
44
+ it "in transaction" do
45
+ User.transaction do
46
+ expect(@user.name).to be_include("slave1")
47
+ data = [
48
+ Address.first.user.name,
49
+ Address.first.prefecture,
50
+ Tel.first.number,
51
+ Tel.first.user.name,
52
+ @user.address.prefecture,
53
+ @user.tels.first.number,
54
+ User.joins(:address).where("addresses.user_id = 1").first.name
55
+ ]
56
+
57
+ expect(data).to be_all{|n| n.include?("master")}
58
+
59
+ end
60
+ end
61
+
62
+ it "specify readonly(false)" do
63
+ data = [
64
+ Address.readonly(false).first.prefecture,
65
+ Address.includes(:user).readonly(false).first.user.name,
66
+ Tel.readonly(false).first.number,
67
+ Tel.includes(:user).readonly(false).first.user.name,
68
+ @user.tels.readonly(false).first.number,
69
+ User.includes(:tels).readonly(false).first.tels.first.number,
70
+ User.includes(:address).readonly(false).first.address.prefecture,
71
+ User.joins(:address).where("addresses.user_id = 1").readonly(false).first.name
72
+ ]
73
+
74
+ expect(data).to be_all{|n| n.include?("master")}
75
+ end
76
+ end
77
+
78
+ context "master_db_only model always access to master" do
79
+ class Address3 < ActiveRecord::Base
80
+ self.table_name = "addresses"
81
+ master_db_only!
82
+ end
83
+
84
+ class Master < ActiveRecord::Base
85
+ self.abstract_class = true
86
+ master_db_only!
87
+ end
88
+
89
+ class Tel3 < Master
90
+ self.table_name = "tels"
91
+ end
92
+
93
+ it "self is master_db_only model" do
94
+ expect(Address3.first.prefecture).to be_include("master")
95
+ end
96
+
97
+ it "parent is master_db_only model" do
98
+ expect(Tel3.first.number).to be_include("master")
99
+ end
100
+
101
+ it "not effect other models" do
102
+ expect(Address.first.prefecture).to be_include("slave1")
103
+ expect(Tel.first.number).to be_include("slave2")
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe "recovery when Mysql down" do
4
+ class User3 < ActiveRecord::Base
5
+ self.table_name = "users"
6
+
7
+ class << self
8
+ attr_writer :limit_time
9
+
10
+ def slave_connection
11
+ @access_time ||= 0
12
+ @access_time += 1
13
+ if @access_time > limit_time
14
+ super
15
+ else
16
+ raise ActiveRecord::StatementInvalid, "MySQL server has gone away"
17
+ end
18
+ end
19
+
20
+ def limit_time
21
+ @limit_time || 1
22
+ end
23
+ end
24
+ end
25
+
26
+ it "enable recovery" do
27
+ User3.limit_time = 1
28
+ expect {
29
+ User3.first
30
+ }.not_to raise_error
31
+ end
32
+
33
+ it "raise exception when retry over" do
34
+ User3.limit_time = 100
35
+ expect {
36
+ User3.first
37
+ }.to raise_error(ActiveRecord::StatementInvalid)
38
+ end
39
+ end
metadata CHANGED
@@ -1,126 +1,199 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: fresh_connection
3
- version: !ruby/object:Gem::Version
4
- hash: 11
5
- prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 8
10
- version: 0.1.8
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Tsukasa OISHI
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2014-01-28 00:00:00 +09:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
11
+ date: 2014-04-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
22
14
  name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
23
21
  prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
27
31
  - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 15
30
- segments:
31
- - 3
32
- - 2
33
- - 0
32
+ - !ruby/object:Gem::Version
34
33
  version: 3.2.0
35
34
  type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: bundler
39
35
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- hash: 9
46
- segments:
47
- - 1
48
- - 3
49
- version: "1.3"
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: railties
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
50
62
  type: :development
51
- version_requirements: *id002
52
- - !ruby/object:Gem::Dependency
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
53
70
  name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 10.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 10.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 2.14.1
90
+ type: :development
54
91
  prerelease: false
55
- requirement: &id003 !ruby/object:Gem::Requirement
56
- none: false
57
- requirements:
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
58
94
  - - ">="
59
- - !ruby/object:Gem::Version
60
- hash: 3
61
- segments:
62
- - 0
63
- version: "0"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.14.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: mysql2
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 0.3.15
64
104
  type: :development
65
- version_requirements: *id003
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 0.3.15
111
+ - !ruby/object:Gem::Dependency
112
+ name: appraisal
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 1.0.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.0.0
66
125
  description: https://github.com/tsukasaoishi/fresh_connection
67
- email:
126
+ email:
68
127
  - tsukasa.oishi@gmail.com
69
128
  executables: []
70
-
71
129
  extensions: []
72
-
73
130
  extra_rdoc_files: []
74
-
75
- files:
131
+ files:
132
+ - ".gitignore"
133
+ - Appraisals
76
134
  - Gemfile
77
135
  - LICENSE.txt
78
136
  - README.md
79
137
  - Rakefile
80
138
  - fresh_connection.gemspec
139
+ - gemfiles/rails3.gemfile
140
+ - gemfiles/rails40.gemfile
141
+ - gemfiles/rails41.gemfile
81
142
  - lib/fresh_connection.rb
82
143
  - lib/fresh_connection/abstract_connection_manager.rb
83
- - lib/fresh_connection/active_record/abstract_adapter.rb
84
- - lib/fresh_connection/active_record/mysql2_adapter.rb
85
- - lib/fresh_connection/active_record/relation.rb
144
+ - lib/fresh_connection/access_control.rb
86
145
  - lib/fresh_connection/connection_manager.rb
146
+ - lib/fresh_connection/extend/ar_base.rb
147
+ - lib/fresh_connection/extend/ar_relation.rb
148
+ - lib/fresh_connection/extend/connection_handler.rb
149
+ - lib/fresh_connection/extend/mysql2_adapter.rb
150
+ - lib/fresh_connection/initializer.rb
87
151
  - lib/fresh_connection/rack/connection_management.rb
88
152
  - lib/fresh_connection/railtie.rb
89
153
  - lib/fresh_connection/slave_connection.rb
154
+ - lib/fresh_connection/slave_connection_handler.rb
90
155
  - lib/fresh_connection/version.rb
91
- has_rdoc: true
156
+ - log/.gitkeep
157
+ - spec/database.yml
158
+ - spec/db_schema.sql
159
+ - spec/prepare.rb
160
+ - spec/spec_helper.rb
161
+ - spec/support/active_record_logger.rb
162
+ - spec/unit/access_control_spec.rb
163
+ - spec/unit/ar_base_spec.rb
164
+ - spec/unit/fresh_connection_spec.rb
165
+ - spec/unit/recovery_spec.rb
92
166
  homepage: https://github.com/tsukasaoishi/fresh_connection
93
- licenses:
167
+ licenses:
94
168
  - MIT
169
+ metadata: {}
95
170
  post_install_message:
96
171
  rdoc_options: []
97
-
98
- require_paths:
172
+ require_paths:
99
173
  - lib
100
- required_ruby_version: !ruby/object:Gem::Requirement
101
- none: false
102
- requirements:
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ requirements:
103
176
  - - ">="
104
- - !ruby/object:Gem::Version
105
- hash: 3
106
- segments:
107
- - 0
108
- version: "0"
109
- required_rubygems_version: !ruby/object:Gem::Requirement
110
- none: false
111
- requirements:
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ requirements:
112
181
  - - ">="
113
- - !ruby/object:Gem::Version
114
- hash: 3
115
- segments:
116
- - 0
117
- version: "0"
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
118
184
  requirements: []
119
-
120
185
  rubyforge_project:
121
- rubygems_version: 1.6.2
186
+ rubygems_version: 2.2.0
122
187
  signing_key:
123
- specification_version: 3
188
+ specification_version: 4
124
189
  summary: FreshConnection supports to connect with Mysql slave servers via Load Balancers.
125
- test_files: []
126
-
190
+ test_files:
191
+ - spec/database.yml
192
+ - spec/db_schema.sql
193
+ - spec/prepare.rb
194
+ - spec/spec_helper.rb
195
+ - spec/support/active_record_logger.rb
196
+ - spec/unit/access_control_spec.rb
197
+ - spec/unit/ar_base_spec.rb
198
+ - spec/unit/fresh_connection_spec.rb
199
+ - spec/unit/recovery_spec.rb