fresh_connection 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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