rubyrep 1.0.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 (140) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +137 -0
  4. data/README.txt +37 -0
  5. data/Rakefile +30 -0
  6. data/bin/rubyrep +8 -0
  7. data/config/hoe.rb +72 -0
  8. data/config/mysql_config.rb +25 -0
  9. data/config/postgres_config.rb +21 -0
  10. data/config/proxied_test_config.rb +14 -0
  11. data/config/redmine_config.rb +17 -0
  12. data/config/rep_config.rb +20 -0
  13. data/config/requirements.rb +32 -0
  14. data/config/test_config.rb +20 -0
  15. data/lib/rubyrep/base_runner.rb +195 -0
  16. data/lib/rubyrep/command_runner.rb +144 -0
  17. data/lib/rubyrep/committers/buffered_committer.rb +140 -0
  18. data/lib/rubyrep/committers/committers.rb +146 -0
  19. data/lib/rubyrep/configuration.rb +240 -0
  20. data/lib/rubyrep/connection_extenders/connection_extenders.rb +133 -0
  21. data/lib/rubyrep/connection_extenders/jdbc_extender.rb +284 -0
  22. data/lib/rubyrep/connection_extenders/mysql_extender.rb +168 -0
  23. data/lib/rubyrep/connection_extenders/postgresql_extender.rb +261 -0
  24. data/lib/rubyrep/database_proxy.rb +52 -0
  25. data/lib/rubyrep/direct_table_scan.rb +75 -0
  26. data/lib/rubyrep/generate_runner.rb +105 -0
  27. data/lib/rubyrep/initializer.rb +39 -0
  28. data/lib/rubyrep/logged_change.rb +326 -0
  29. data/lib/rubyrep/proxied_table_scan.rb +171 -0
  30. data/lib/rubyrep/proxy_block_cursor.rb +145 -0
  31. data/lib/rubyrep/proxy_connection.rb +318 -0
  32. data/lib/rubyrep/proxy_cursor.rb +44 -0
  33. data/lib/rubyrep/proxy_row_cursor.rb +43 -0
  34. data/lib/rubyrep/proxy_runner.rb +89 -0
  35. data/lib/rubyrep/replication_difference.rb +91 -0
  36. data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
  37. data/lib/rubyrep/replication_extenders/postgresql_replication.rb +204 -0
  38. data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
  39. data/lib/rubyrep/replication_helper.rb +104 -0
  40. data/lib/rubyrep/replication_initializer.rb +307 -0
  41. data/lib/rubyrep/replication_run.rb +48 -0
  42. data/lib/rubyrep/replication_runner.rb +138 -0
  43. data/lib/rubyrep/replicators/replicators.rb +37 -0
  44. data/lib/rubyrep/replicators/two_way_replicator.rb +334 -0
  45. data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
  46. data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
  47. data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
  48. data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
  49. data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
  50. data/lib/rubyrep/scan_runner.rb +25 -0
  51. data/lib/rubyrep/session.rb +177 -0
  52. data/lib/rubyrep/sync_helper.rb +111 -0
  53. data/lib/rubyrep/sync_runner.rb +31 -0
  54. data/lib/rubyrep/syncers/syncers.rb +112 -0
  55. data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
  56. data/lib/rubyrep/table_scan.rb +54 -0
  57. data/lib/rubyrep/table_scan_helper.rb +38 -0
  58. data/lib/rubyrep/table_sorter.rb +70 -0
  59. data/lib/rubyrep/table_spec_resolver.rb +136 -0
  60. data/lib/rubyrep/table_sync.rb +68 -0
  61. data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
  62. data/lib/rubyrep/type_casting_cursor.rb +31 -0
  63. data/lib/rubyrep/uninstall_runner.rb +92 -0
  64. data/lib/rubyrep/version.rb +9 -0
  65. data/lib/rubyrep.rb +68 -0
  66. data/script/destroy +14 -0
  67. data/script/generate +14 -0
  68. data/script/txt2html +74 -0
  69. data/setup.rb +1585 -0
  70. data/sims/performance/big_rep_spec.rb +100 -0
  71. data/sims/performance/big_scan_spec.rb +57 -0
  72. data/sims/performance/big_sync_spec.rb +141 -0
  73. data/sims/performance/performance.rake +228 -0
  74. data/sims/sim_helper.rb +24 -0
  75. data/spec/base_runner_spec.rb +218 -0
  76. data/spec/buffered_committer_spec.rb +271 -0
  77. data/spec/command_runner_spec.rb +145 -0
  78. data/spec/committers_spec.rb +174 -0
  79. data/spec/configuration_spec.rb +198 -0
  80. data/spec/connection_extender_interface_spec.rb +138 -0
  81. data/spec/connection_extenders_registration_spec.rb +129 -0
  82. data/spec/database_proxy_spec.rb +48 -0
  83. data/spec/database_rake_spec.rb +40 -0
  84. data/spec/db_specific_connection_extenders_spec.rb +34 -0
  85. data/spec/db_specific_replication_extenders_spec.rb +38 -0
  86. data/spec/direct_table_scan_spec.rb +61 -0
  87. data/spec/generate_runner_spec.rb +84 -0
  88. data/spec/initializer_spec.rb +46 -0
  89. data/spec/logged_change_spec.rb +480 -0
  90. data/spec/postgresql_replication_spec.rb +48 -0
  91. data/spec/postgresql_support_spec.rb +57 -0
  92. data/spec/progress_bar_spec.rb +77 -0
  93. data/spec/proxied_table_scan_spec.rb +151 -0
  94. data/spec/proxy_block_cursor_spec.rb +197 -0
  95. data/spec/proxy_connection_spec.rb +399 -0
  96. data/spec/proxy_cursor_spec.rb +56 -0
  97. data/spec/proxy_row_cursor_spec.rb +66 -0
  98. data/spec/proxy_runner_spec.rb +70 -0
  99. data/spec/replication_difference_spec.rb +160 -0
  100. data/spec/replication_extender_interface_spec.rb +365 -0
  101. data/spec/replication_extenders_spec.rb +32 -0
  102. data/spec/replication_helper_spec.rb +121 -0
  103. data/spec/replication_initializer_spec.rb +477 -0
  104. data/spec/replication_run_spec.rb +166 -0
  105. data/spec/replication_runner_spec.rb +213 -0
  106. data/spec/replicators_spec.rb +31 -0
  107. data/spec/rubyrep_spec.rb +8 -0
  108. data/spec/scan_detail_reporter_spec.rb +119 -0
  109. data/spec/scan_progress_printers_spec.rb +68 -0
  110. data/spec/scan_report_printers_spec.rb +67 -0
  111. data/spec/scan_runner_spec.rb +50 -0
  112. data/spec/scan_summary_reporter_spec.rb +61 -0
  113. data/spec/session_spec.rb +212 -0
  114. data/spec/spec.opts +1 -0
  115. data/spec/spec_helper.rb +295 -0
  116. data/spec/sync_helper_spec.rb +157 -0
  117. data/spec/sync_runner_spec.rb +78 -0
  118. data/spec/syncers_spec.rb +171 -0
  119. data/spec/table_scan_helper_spec.rb +29 -0
  120. data/spec/table_scan_spec.rb +49 -0
  121. data/spec/table_sorter_spec.rb +31 -0
  122. data/spec/table_spec_resolver_spec.rb +102 -0
  123. data/spec/table_sync_spec.rb +84 -0
  124. data/spec/trigger_mode_switcher_spec.rb +83 -0
  125. data/spec/two_way_replicator_spec.rb +551 -0
  126. data/spec/two_way_syncer_spec.rb +256 -0
  127. data/spec/type_casting_cursor_spec.rb +50 -0
  128. data/spec/uninstall_runner_spec.rb +86 -0
  129. data/tasks/database.rake +439 -0
  130. data/tasks/deployment.rake +29 -0
  131. data/tasks/environment.rake +9 -0
  132. data/tasks/java.rake +37 -0
  133. data/tasks/redmine_test.rake +47 -0
  134. data/tasks/rspec.rake +68 -0
  135. data/tasks/rubyrep.tailor +18 -0
  136. data/tasks/stats.rake +19 -0
  137. data/tasks/task_helper.rb +20 -0
  138. data.tar.gz.sig +0 -0
  139. metadata +243 -0
  140. metadata.gz.sig +0 -0
@@ -0,0 +1,174 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ include RR
4
+
5
+ describe Committers do
6
+ before(:each) do
7
+ @old_committers = Committers.committers
8
+ end
9
+
10
+ after(:each) do
11
+ Committers.instance_variable_set :@committers, @old_committers
12
+ end
13
+
14
+ it "committers should return empty hash if nil" do
15
+ Committers.instance_variable_set :@committers, nil
16
+ Committers.committers.should == {}
17
+ end
18
+
19
+ it "committers should return the registered committers" do
20
+ Committers.instance_variable_set :@committers, :dummy_data
21
+ Committers.committers.should == :dummy_data
22
+ end
23
+
24
+ it "register should register the provided commiter" do
25
+ Committers.instance_variable_set :@committers, nil
26
+ Committers.register :a_key => :a
27
+ Committers.register :b_key => :b
28
+ Committers.committers[:a_key].should == :a
29
+ Committers.committers[:b_key].should == :b
30
+ end
31
+ end
32
+
33
+
34
+ describe "Committer", :shared => true do
35
+ it "should support the right constructor interface" do
36
+ session = mock("session")
37
+ session.should_receive(:left).any_number_of_times \
38
+ .and_return(mock("left connection", :null_object => true))
39
+ session.should_receive(:right).any_number_of_times \
40
+ .and_return(mock("right connection", :null_object => true))
41
+ @committer.class.new session
42
+ end
43
+
44
+ it "should proxy insert_record, update_record and delete_record calls" do
45
+ left_connection = mock("left connection", :null_object => true)
46
+ left_connection.should_receive(:insert_record).with("left", :dummy_insert_values)
47
+
48
+ right_connection = mock("right connection", :null_object => true)
49
+ right_connection.should_receive(:update_record).with("right", :dummy_update_values, :dummy_org_key)
50
+ right_connection.should_receive(:delete_record).with("right", :dummy_delete_values)
51
+
52
+ session = mock("session")
53
+ session.should_receive(:left).any_number_of_times.and_return(left_connection)
54
+ session.should_receive(:right).any_number_of_times.and_return(right_connection)
55
+
56
+ committer = @committer.class.new session
57
+
58
+ committer.insert_record :left, 'left', :dummy_insert_values
59
+ committer.update_record :right, 'right', :dummy_update_values, :dummy_org_key
60
+ committer.delete_record :right, 'right', :dummy_delete_values
61
+ end
62
+
63
+ it "should support finalize" do
64
+ @committer.finalize(false)
65
+ end
66
+ end
67
+
68
+ describe Committers::DefaultCommitter do
69
+ before(:each) do
70
+ @session = mock("session")
71
+ @session.should_receive(:left).any_number_of_times.and_return(:left_connection)
72
+ @session.should_receive(:right).any_number_of_times.and_return(:right_connection)
73
+ @committer = Committers::DefaultCommitter.new @session
74
+ end
75
+
76
+ it "should register itself" do
77
+ Committers.committers[:default].should == Committers::DefaultCommitter
78
+ end
79
+
80
+ it "initialize should store the provided parameters" do
81
+ @committer.session.should == @session
82
+ @committer.connections \
83
+ .should == {:left => @session.left, :right => @session.right}
84
+ end
85
+
86
+ it_should_behave_like "Committer"
87
+ end
88
+
89
+ describe Committers::NeverCommitter do
90
+ before(:each) do
91
+ @old_session = Committers::NeverCommitter.current_session
92
+ Committers::NeverCommitter.current_session = nil
93
+ @session = mock("session")
94
+ @session.should_receive(:left).any_number_of_times \
95
+ .and_return(mock("left connection", :null_object => true))
96
+ @session.should_receive(:right).any_number_of_times \
97
+ .and_return(mock("right connection", :null_object => true))
98
+ @committer = Committers::NeverCommitter.new @session
99
+ end
100
+
101
+ after(:each) do
102
+ Committers::NeverCommitter.current_session = @old_session
103
+ end
104
+
105
+ it "should register itself" do
106
+ Committers.committers[:never_commit].should == Committers::NeverCommitter
107
+ end
108
+
109
+ it "initialize should store the provided parameters" do
110
+ @committer.session.should == @session
111
+ @committer.connections \
112
+ .should == {:left => @session.left, :right => @session.right}
113
+ end
114
+
115
+ it "initialize should rollback the previous current session and then register the new one as current session" do
116
+ old_session = mock("old session", :null_object => true)
117
+ new_session = mock("new session", :null_object => true)
118
+ Committers::NeverCommitter.current_session = old_session
119
+ Committers::NeverCommitter.should_receive(:rollback_current_session)
120
+
121
+ Committers::NeverCommitter.new new_session
122
+ Committers::NeverCommitter.current_session.should == new_session
123
+ end
124
+
125
+ it "initialize should start new transactions" do
126
+ # Ensure that initialize handles the case of no previous database session
127
+ # being present
128
+ Committers::NeverCommitter.current_session = nil
129
+ new_session = mock("new session")
130
+
131
+ left_connection = mock("left connection")
132
+ left_connection.should_receive :begin_db_transaction
133
+ new_session.should_receive(:left).any_number_of_times.and_return(left_connection)
134
+
135
+ right_connection = mock("right connection")
136
+ right_connection.should_receive :begin_db_transaction
137
+ new_session.should_receive(:right).any_number_of_times.and_return(right_connection)
138
+
139
+ @committer = Committers::NeverCommitter.new new_session
140
+ end
141
+
142
+ it "rollback_current_session should rollback current session" do
143
+ old_session = mock("old session")
144
+
145
+ left_connection = mock("left connection")
146
+ left_connection.should_receive :rollback_db_transaction
147
+ old_session.should_receive(:left).and_return(left_connection)
148
+
149
+ right_connection = mock("right connection")
150
+ right_connection.should_receive :rollback_db_transaction
151
+ old_session.should_receive(:right).and_return(right_connection)
152
+
153
+ Committers::NeverCommitter.current_session = old_session
154
+ Committers::NeverCommitter.rollback_current_session
155
+ end
156
+
157
+ it "should work will real sessions" do
158
+ session = Session.new(standard_config)
159
+ Committers::NeverCommitter.new session
160
+ Committers::NeverCommitter.new session
161
+ Committers::NeverCommitter.rollback_current_session
162
+ end
163
+
164
+ it "should work will real proxied sessions" do
165
+ ensure_proxy
166
+ session = Session.new(proxied_config)
167
+ Committers::NeverCommitter.new session
168
+ Committers::NeverCommitter.new session
169
+ Committers::NeverCommitter.rollback_current_session
170
+ end
171
+
172
+ it_should_behave_like "Committer"
173
+
174
+ end
@@ -0,0 +1,198 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ include RR
4
+
5
+ describe Configuration do
6
+ before(:each) do
7
+ end
8
+
9
+ it "initialize should set #left and #right to empty hashes" do
10
+ config = Configuration.new
11
+ config.left.should == {}
12
+ config.right.should == {}
13
+ end
14
+
15
+ it "initialize should set #options to the default options" do
16
+ config = Configuration.new
17
+ config.options.should == Configuration::DEFAULT_OPTIONS
18
+ end
19
+
20
+ it "options= should merge the provided into the existing options" do
21
+ config = Configuration.new
22
+ config.options = {:bla => :bla}
23
+ config.options = {:bla => :blub}
24
+ config.options[:bla].should == :blub
25
+ end
26
+
27
+ it "each_matching_option should yield if general option matches" do
28
+ config = Configuration.new
29
+ config.options = {:bla => :blub}
30
+ yielded = []
31
+ config.each_matching_option(:bla) {|spec, value| yielded << [spec, value]}
32
+ yielded.should == [[nil, :blub]]
33
+ end
34
+
35
+ it "each_matching_option should yield if table specific options match" do
36
+ config = Configuration.new
37
+ config.options = {:a => 1}
38
+ config.add_table_options 't1', :a => 2
39
+ config.add_table_options 't2', :b => 3
40
+ config.add_table_options 't3', :a => 4
41
+ yielded = []
42
+ config.each_matching_option(:a) {|spec, value| yielded << [spec, value]}
43
+ yielded.should == [
44
+ [nil, 1],
45
+ ['t1', 2],
46
+ ['t3', 4]
47
+ ]
48
+ end
49
+
50
+ it "each_matching_option should not yield unmatching options" do
51
+ config = Configuration.new
52
+ config.options = {:a => :blub}
53
+ config.add_table_options 'dummy_table', :b => :blub
54
+ yielded = []
55
+ config.each_matching_option(:c) {|spec, value| yielded << [spec, value]}
56
+ yielded.should == []
57
+ end
58
+
59
+ it "options_for_table should return the general options if there are no table specific options at all" do
60
+ config = Configuration.new
61
+ config.options_for_table('b').should == \
62
+ Syncers::TwoWaySyncer.default_options.clone.
63
+ merge(config.options)
64
+ end
65
+
66
+ it "included_table_specs should return the list of included table specifications" do
67
+ config = Configuration.new
68
+ config.include_tables('a', {:bla => :blub})
69
+ config.include_tables('a, b')
70
+ config.include_tables(/a/)
71
+ config.included_table_specs.should == ['a', 'a, b', /a/]
72
+ end
73
+
74
+ it "included_table_specs should save the options if provided" do
75
+ config = Configuration.new
76
+ config.include_tables('a', {:bla => :blub})
77
+ config.options_for_table('a')[:bla].should == :blub
78
+ end
79
+
80
+ it "include_tables should include the specified table specs" do
81
+ config = Configuration.new
82
+ config.include_tables('a')
83
+ config.include_tables(/b/)
84
+ config.included_table_specs.include?('a').should be_true
85
+ config.included_table_specs.include?(/b/).should be_true
86
+ end
87
+
88
+ it "include_table should alias to include_tables" do
89
+ config = Configuration.new
90
+ config.include_table('a')
91
+ config.included_table_specs.include?('a').should be_true
92
+ end
93
+
94
+ it "exclude_tables should exclude the specified table specs" do
95
+ config = Configuration.new
96
+ config.exclude_tables('a')
97
+ config.exclude_tables(/b/)
98
+ config.excluded_table_specs.include?('a').should be_true
99
+ config.excluded_table_specs.include?(/b/).should be_true
100
+ end
101
+
102
+ it "exclude_table should alias to exclude_tables" do
103
+ config = Configuration.new
104
+ config.exclude_table('a')
105
+ config.excluded_table_specs.include?('a').should be_true
106
+ end
107
+
108
+ it "exclude_rubyrep_tables should exclude the rubyrep infrastructure tables" do
109
+ config = Configuration.new
110
+ config.exclude_rubyrep_tables
111
+ config.excluded_table_specs.include?(/^rr_.*/).should be_true
112
+ end
113
+
114
+ it "excluded_table_specs should return the list of excluded table specifications" do
115
+ config = Configuration.new
116
+ config.exclude_tables('a')
117
+ config.exclude_tables('a, b')
118
+ config.exclude_tables(/a/)
119
+ config.excluded_table_specs.should == ['a', 'a, b', /a/]
120
+ end
121
+
122
+ it "options_for_table should return the general options if there are no matching table specific options" do
123
+ config = Configuration.new
124
+ config.include_tables(/a/, {:bla => :blub})
125
+ config.options_for_table('b').should == \
126
+ Syncers::TwoWaySyncer.default_options.clone.
127
+ merge(config.options)
128
+ end
129
+
130
+ it "options_for_table should return table specific options mixed in with default options" do
131
+ config = Configuration.new
132
+ config.include_tables(/a/, {:bla => :blub})
133
+ config.options_for_table('a').should == \
134
+ Syncers::TwoWaySyncer.default_options.clone.
135
+ merge(config.options).
136
+ merge(:bla => :blub)
137
+ end
138
+
139
+ it "options_for_table should return last added version of added options for matching table spec" do
140
+ config = Configuration.new
141
+ config.include_tables(/a/, {:bla => :blub})
142
+ config.include_tables('a', {:bla => :blok})
143
+ config.include_tables(/x/, {:bla => :bar})
144
+ config.include_tables('y', {:bla => :foo})
145
+ config.options_for_table('a').should == \
146
+ Syncers::TwoWaySyncer.default_options.clone.
147
+ merge(config.options).
148
+ merge(:bla => :blok)
149
+ end
150
+
151
+ it "options_for_table should match against table pair specs" do
152
+ config = Configuration.new
153
+ config.add_table_options('a, b', {:bla => :blub})
154
+ config.options_for_table('a')[:bla].should == :blub
155
+ end
156
+
157
+ it "options_for_table should match against regular expression specs" do
158
+ config = Configuration.new
159
+ config.add_table_options(/a/, {:bla => :blub})
160
+ config.options_for_table('a')[:bla].should == :blub
161
+ end
162
+
163
+ it "options_for_table should match against pure table name specs" do
164
+ config = Configuration.new
165
+ config.add_table_options('a', {:bla => :blub})
166
+ config.options_for_table('a')[:bla].should == :blub
167
+ end
168
+
169
+ it "add_table_options should not create table_spec duplicates" do
170
+ config = Configuration.new
171
+ config.add_table_options(/a/, {:bla => :blub})
172
+ config.add_table_options(/a/, {:foo => :bar})
173
+ config.options_for_table('a').should == \
174
+ Syncers::TwoWaySyncer.default_options.clone.
175
+ merge(config.options).
176
+ merge(:bla => :blub, :foo => :bar)
177
+ end
178
+
179
+ it "add_table_option should alias to add_table_options" do
180
+ config = Configuration.new
181
+ config.add_table_option(/a/, {:bla => :blub})
182
+ config.options_for_table('a')[:bla].should == :blub
183
+ end
184
+
185
+ it "add_table_options should include default syncer options" do
186
+ config = Configuration.new
187
+ config.options = {:syncer => :one_way}
188
+
189
+ # overwrite one syncer option
190
+ config.add_table_options(/a/, {:delete => true})
191
+
192
+ options = config.options_for_table('a')
193
+ Syncers::OneWaySyncer.default_options.each do |key, value|
194
+ options[key].should == value unless key == :delete
195
+ end
196
+ options[:delete].should == true
197
+ end
198
+ end
@@ -0,0 +1,138 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require 'yaml'
3
+
4
+ include RR
5
+
6
+ # All ConnectionExtenders need to pass this spec
7
+ describe "ConnectionExtender", :shared => true do
8
+ before(:each) do
9
+ end
10
+
11
+ it "primary_key_names should return primary key names ordered as per primary key index" do
12
+ session = Session.new
13
+ session.left.primary_key_names('extender_combined_key').should == ['first_id', 'second_id']
14
+
15
+ session.left.primary_key_names('extender_inverted_combined_key') \
16
+ .should == ['second_id', 'first_id']
17
+ end
18
+
19
+ it "primary_key_names should return an empty array for tables without any primary key" do
20
+ session = Session.new
21
+ session.left.primary_key_names('extender_without_key') \
22
+ .should == []
23
+ end
24
+
25
+ it "primary_key_names called for a non-existing table should throw an exception" do
26
+ session = Session.new
27
+ lambda {session.left.primary_key_names('non_existing_table')} \
28
+ .should raise_error(RuntimeError, /.*non_existing_table.*not exist/)
29
+ end
30
+
31
+ it "referenced_tables should identify the correct table dependencies" do
32
+ session = Session.new
33
+ referenced_tables = session.left.referenced_tables(['scanner_records', 'referencing_table'])
34
+ referenced_tables.size.should == 2
35
+ referenced_tables['scanner_records'].should == []
36
+ referenced_tables['referencing_table'].sort.
37
+ should == ["referenced_table", "referenced_table2"]
38
+ end
39
+
40
+ it "referenced_tables should return those tables without primary key" do
41
+ session = Session.new
42
+ referenced_tables = session.left.referenced_tables(['table_with_manual_key'])
43
+ referenced_tables.should == {'table_with_manual_key' => []}
44
+ end
45
+
46
+ it "select_cursor should handle zero result queries" do
47
+ session = Session.new
48
+ result = session.left.select_cursor :table => 'extender_no_record'
49
+ result.next?.should be_false
50
+ end
51
+
52
+ it "select_cursor should work if row_buffer_size is smaller than table size" do
53
+ session = Session.new
54
+ result = session.left.select_cursor(:table => 'scanner_records', :row_buffer_size => 2)
55
+ result.next_row
56
+ result.next_row
57
+ result.next_row['id'].should == '3'
58
+ result.clear
59
+ end
60
+
61
+ it "select_cursor should allow iterating through records" do
62
+ session = Session.new
63
+ result = session.left.select_cursor :table => 'extender_one_record'
64
+ result.next?.should be_true
65
+ result.next_row.should == {'id' => "1", 'name' => 'Alice'}
66
+ end
67
+
68
+ it "select_cursor next_row should raise if there are no records" do
69
+ session = Session.new
70
+ result = session.left.select_cursor :table => 'extender_no_record'
71
+ lambda {result.next_row}.should raise_error(RuntimeError, 'no more rows available')
72
+ end
73
+
74
+ it "select_cursor next_row should handle multi byte characters correctly" do
75
+ session = Session.new
76
+ result = session.left.select_cursor :query => "select id, multi_byte from extender_type_check"
77
+ row = result.next_row
78
+ row.should == {
79
+ 'id' => "1",
80
+ 'multi_byte' => "よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor."
81
+ }
82
+ end
83
+
84
+ it "select_cursor should read null values correctly" do
85
+ session = Session.new
86
+ result = session.left.select_cursor(
87
+ :table => 'extender_combined_key',
88
+ :row_keys => [{'first_id' => 3, 'second_id' => 1}]
89
+ )
90
+ result.next_row.should == {'first_id' => '3', 'second_id' => '1', 'name' => nil}
91
+ end
92
+
93
+ it "should read and write binary data correctly" do
94
+ session = Session.new
95
+
96
+ org_data = Marshal.dump(['bla',:dummy,1,2,3])
97
+ result_data = nil
98
+ begin
99
+ session.left.begin_db_transaction
100
+ sql = "insert into extender_type_check(id, binary_test) values(2, '#{org_data}')"
101
+ session.left.execute sql
102
+
103
+ org_cursor = session.left.select_cursor(:query => "select id, binary_test from extender_type_check where id = 2")
104
+ cursor = TypeCastingCursor.new session.left, 'extender_type_check', org_cursor
105
+ result_data = cursor.next_row['binary_test']
106
+ ensure
107
+ session.left.rollback_db_transaction
108
+ end
109
+ result_data.should == org_data
110
+ end
111
+
112
+ it "should read and write text data correctly" do
113
+ session = Session.new
114
+
115
+ org_data = "よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor."
116
+ result_data = nil
117
+ begin
118
+ session.left.begin_db_transaction
119
+ sql = "insert into extender_type_check(id, text_test) values(2, '#{org_data}')"
120
+ session.left.execute sql
121
+
122
+ org_cursor = session.left.select_cursor(:query => "select id, text_test from extender_type_check where id = 2")
123
+ cursor = TypeCastingCursor.new session.left, 'extender_type_check', org_cursor
124
+ result_data = cursor.next_row['text_test']
125
+ ensure
126
+ session.left.rollback_db_transaction
127
+ end
128
+ result_data.should == org_data
129
+ end
130
+
131
+ it "cursors returned by select_cursor should support clear" do
132
+ session = Session.new
133
+ result = session.left.select_cursor :table => 'extender_one_record'
134
+ result.next?.should be_true
135
+ result.should respond_to(:clear)
136
+ result.clear
137
+ end
138
+ end
@@ -0,0 +1,129 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ include RR
4
+
5
+ describe ConnectionExtenders, "Registration" do
6
+ before(:each) do
7
+ Initializer.configuration = standard_config
8
+ @@old_cache_status = ConnectionExtenders.use_db_connection_cache(false)
9
+ end
10
+
11
+ after(:each) do
12
+ ConnectionExtenders.use_db_connection_cache(@@old_cache_status)
13
+ end
14
+
15
+ it "extenders should return list of registered connection extenders" do
16
+ ConnectionExtenders.extenders.include?(:postgresql).should be_true
17
+ end
18
+
19
+ it "register should register a new connection extender" do
20
+ ConnectionExtenders.register(:bla => :blub)
21
+
22
+ ConnectionExtenders.extenders.include?(:bla).should be_true
23
+ end
24
+
25
+ it "register should replace already existing connection extenders" do
26
+ ConnectionExtenders.register(:bla => :blub)
27
+ ConnectionExtenders.register(:bla => :blub2)
28
+
29
+ ConnectionExtenders.extenders[:bla].should == :blub2
30
+ end
31
+
32
+ it "initialize should establish the database connections" do
33
+ mock_active_record :once
34
+
35
+ ConnectionExtenders.db_connect Initializer.configuration.left
36
+ end
37
+
38
+ it "db_connect should use jdbc configuration adapter and extender under jruby" do
39
+ fake_ruby_platform 'java' do
40
+ mock_active_record :once
41
+ used_extender = nil
42
+ ConnectionExtenders.extenders.should_receive('[]'.to_sym).once \
43
+ .and_return {|extender| used_extender = extender }
44
+
45
+ configuration = deep_copy(Initializer.configuration)
46
+ configuration.left[:adapter] = 'dummyadapter'
47
+
48
+ ConnectionExtenders.db_connect configuration.left
49
+
50
+ $used_config[:adapter].should == "jdbcdummyadapter"
51
+ used_extender.should == :jdbc
52
+ end
53
+ end
54
+
55
+ it "db_connect created connections should be alive" do
56
+ connection = ConnectionExtenders.db_connect Initializer.configuration.left
57
+
58
+ connection.should be_active
59
+ end
60
+
61
+ it "db_connect should include the connection extender into connection" do
62
+ connection = ConnectionExtenders.db_connect Initializer.configuration.left
63
+
64
+ connection.should respond_to(:select_cursor)
65
+ end
66
+
67
+ it "db_connect should raise an Exception if no fitting connection extender is available" do
68
+ # If unknown connection adapters are encountered in jruby, then we
69
+ # automatically use JdbcExtender.
70
+ # Means that this test only makes sense if not running on jruby
71
+ if not RUBY_PLATFORM =~ /java/
72
+ mock_active_record :once
73
+
74
+ config = deep_copy(Initializer.configuration)
75
+
76
+ config.left[:adapter] = 'dummy'
77
+
78
+ lambda {ConnectionExtenders.db_connect config.left}.should raise_error(RuntimeError, /dummy/)
79
+ end
80
+ end
81
+
82
+ it "use_db_connection_cache should set the new cache status and return the old one" do
83
+ ConnectionExtenders.use_db_connection_cache :first_status
84
+ first_status = ConnectionExtenders.use_db_connection_cache :second_status
85
+ second_status = ConnectionExtenders.use_db_connection_cache :whatever
86
+ first_status.should == :first_status
87
+ second_status.should == :second_status
88
+ end
89
+
90
+ it "clear_db_connection_cache should clear the connection cache" do
91
+ old_cache = ConnectionExtenders.connection_cache
92
+ begin
93
+ ConnectionExtenders.connection_cache = :dummy_cache
94
+ ConnectionExtenders.clear_db_connection_cache
95
+ ConnectionExtenders.connection_cache.should == {}
96
+ ensure
97
+ ConnectionExtenders.connection_cache = old_cache
98
+ end
99
+ end
100
+
101
+ it "db_connect should create the database connection if not yet cached" do
102
+ old_cache = ConnectionExtenders.connection_cache
103
+ begin
104
+ ConnectionExtenders.clear_db_connection_cache
105
+ mock_active_record :once
106
+ ConnectionExtenders.use_db_connection_cache true
107
+ ConnectionExtenders.db_connect Initializer.configuration.left
108
+ ConnectionExtenders.connection_cache.should_not be_empty
109
+ ensure
110
+ ConnectionExtenders.connection_cache = old_cache
111
+ end
112
+ end
113
+
114
+ it "db_connect should not create the database connection if already cached and alive" do
115
+ old_cache = ConnectionExtenders.connection_cache
116
+ begin
117
+ ConnectionExtenders.clear_db_connection_cache
118
+ mock_active_record :once # only mocked once even though db_connect is called twice
119
+ ConnectionExtenders.use_db_connection_cache true
120
+ connection = ConnectionExtenders.db_connect Initializer.configuration.left
121
+ connection.should_receive(:active?).and_return(:true)
122
+ ConnectionExtenders.db_connect Initializer.configuration.left
123
+ ensure
124
+ ConnectionExtenders.connection_cache = old_cache
125
+ end
126
+ end
127
+
128
+ end
129
+
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ include RR
4
+
5
+ describe DatabaseProxy do
6
+ before(:each) do
7
+ Initializer.configuration = standard_config
8
+ end
9
+
10
+ it "initialize should create an empty session regiser" do
11
+ proxy = DatabaseProxy.new
12
+ proxy.session_register.should == {}
13
+ end
14
+
15
+ def create_proxy_and_session
16
+ proxy = DatabaseProxy.new
17
+ session = proxy.create_session Initializer.configuration.left
18
+ return proxy, session
19
+ end
20
+
21
+ it "create_session should register the created session" do
22
+ proxy, session = create_proxy_and_session
23
+
24
+ session.should be_an_instance_of(ProxyConnection)
25
+ proxy.session_register.include?(session).should == true
26
+ end
27
+
28
+ it "destroy_session should destroy and unregister the session" do
29
+ proxy, session = create_proxy_and_session
30
+ session.should_receive(:destroy)
31
+
32
+ proxy.destroy_session session
33
+
34
+ proxy.session_register.include?(session).should == false
35
+ end
36
+
37
+ it "ping should respond with 'pong'" do
38
+ proxy = DatabaseProxy.new
39
+ proxy.ping.should == 'pong'
40
+ end
41
+
42
+ it "terminate should exit the proxy" do
43
+ proxy = DatabaseProxy.new
44
+ Thread.main.should_receive(:raise).with(SystemExit)
45
+
46
+ proxy.terminate!
47
+ end
48
+ end