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.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +137 -0
- data/README.txt +37 -0
- data/Rakefile +30 -0
- data/bin/rubyrep +8 -0
- data/config/hoe.rb +72 -0
- data/config/mysql_config.rb +25 -0
- data/config/postgres_config.rb +21 -0
- data/config/proxied_test_config.rb +14 -0
- data/config/redmine_config.rb +17 -0
- data/config/rep_config.rb +20 -0
- data/config/requirements.rb +32 -0
- data/config/test_config.rb +20 -0
- data/lib/rubyrep/base_runner.rb +195 -0
- data/lib/rubyrep/command_runner.rb +144 -0
- data/lib/rubyrep/committers/buffered_committer.rb +140 -0
- data/lib/rubyrep/committers/committers.rb +146 -0
- data/lib/rubyrep/configuration.rb +240 -0
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +133 -0
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +284 -0
- data/lib/rubyrep/connection_extenders/mysql_extender.rb +168 -0
- data/lib/rubyrep/connection_extenders/postgresql_extender.rb +261 -0
- data/lib/rubyrep/database_proxy.rb +52 -0
- data/lib/rubyrep/direct_table_scan.rb +75 -0
- data/lib/rubyrep/generate_runner.rb +105 -0
- data/lib/rubyrep/initializer.rb +39 -0
- data/lib/rubyrep/logged_change.rb +326 -0
- data/lib/rubyrep/proxied_table_scan.rb +171 -0
- data/lib/rubyrep/proxy_block_cursor.rb +145 -0
- data/lib/rubyrep/proxy_connection.rb +318 -0
- data/lib/rubyrep/proxy_cursor.rb +44 -0
- data/lib/rubyrep/proxy_row_cursor.rb +43 -0
- data/lib/rubyrep/proxy_runner.rb +89 -0
- data/lib/rubyrep/replication_difference.rb +91 -0
- data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
- data/lib/rubyrep/replication_extenders/postgresql_replication.rb +204 -0
- data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
- data/lib/rubyrep/replication_helper.rb +104 -0
- data/lib/rubyrep/replication_initializer.rb +307 -0
- data/lib/rubyrep/replication_run.rb +48 -0
- data/lib/rubyrep/replication_runner.rb +138 -0
- data/lib/rubyrep/replicators/replicators.rb +37 -0
- data/lib/rubyrep/replicators/two_way_replicator.rb +334 -0
- data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
- data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
- data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
- data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
- data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
- data/lib/rubyrep/scan_runner.rb +25 -0
- data/lib/rubyrep/session.rb +177 -0
- data/lib/rubyrep/sync_helper.rb +111 -0
- data/lib/rubyrep/sync_runner.rb +31 -0
- data/lib/rubyrep/syncers/syncers.rb +112 -0
- data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
- data/lib/rubyrep/table_scan.rb +54 -0
- data/lib/rubyrep/table_scan_helper.rb +38 -0
- data/lib/rubyrep/table_sorter.rb +70 -0
- data/lib/rubyrep/table_spec_resolver.rb +136 -0
- data/lib/rubyrep/table_sync.rb +68 -0
- data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
- data/lib/rubyrep/type_casting_cursor.rb +31 -0
- data/lib/rubyrep/uninstall_runner.rb +92 -0
- data/lib/rubyrep/version.rb +9 -0
- data/lib/rubyrep.rb +68 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/sims/performance/big_rep_spec.rb +100 -0
- data/sims/performance/big_scan_spec.rb +57 -0
- data/sims/performance/big_sync_spec.rb +141 -0
- data/sims/performance/performance.rake +228 -0
- data/sims/sim_helper.rb +24 -0
- data/spec/base_runner_spec.rb +218 -0
- data/spec/buffered_committer_spec.rb +271 -0
- data/spec/command_runner_spec.rb +145 -0
- data/spec/committers_spec.rb +174 -0
- data/spec/configuration_spec.rb +198 -0
- data/spec/connection_extender_interface_spec.rb +138 -0
- data/spec/connection_extenders_registration_spec.rb +129 -0
- data/spec/database_proxy_spec.rb +48 -0
- data/spec/database_rake_spec.rb +40 -0
- data/spec/db_specific_connection_extenders_spec.rb +34 -0
- data/spec/db_specific_replication_extenders_spec.rb +38 -0
- data/spec/direct_table_scan_spec.rb +61 -0
- data/spec/generate_runner_spec.rb +84 -0
- data/spec/initializer_spec.rb +46 -0
- data/spec/logged_change_spec.rb +480 -0
- data/spec/postgresql_replication_spec.rb +48 -0
- data/spec/postgresql_support_spec.rb +57 -0
- data/spec/progress_bar_spec.rb +77 -0
- data/spec/proxied_table_scan_spec.rb +151 -0
- data/spec/proxy_block_cursor_spec.rb +197 -0
- data/spec/proxy_connection_spec.rb +399 -0
- data/spec/proxy_cursor_spec.rb +56 -0
- data/spec/proxy_row_cursor_spec.rb +66 -0
- data/spec/proxy_runner_spec.rb +70 -0
- data/spec/replication_difference_spec.rb +160 -0
- data/spec/replication_extender_interface_spec.rb +365 -0
- data/spec/replication_extenders_spec.rb +32 -0
- data/spec/replication_helper_spec.rb +121 -0
- data/spec/replication_initializer_spec.rb +477 -0
- data/spec/replication_run_spec.rb +166 -0
- data/spec/replication_runner_spec.rb +213 -0
- data/spec/replicators_spec.rb +31 -0
- data/spec/rubyrep_spec.rb +8 -0
- data/spec/scan_detail_reporter_spec.rb +119 -0
- data/spec/scan_progress_printers_spec.rb +68 -0
- data/spec/scan_report_printers_spec.rb +67 -0
- data/spec/scan_runner_spec.rb +50 -0
- data/spec/scan_summary_reporter_spec.rb +61 -0
- data/spec/session_spec.rb +212 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +295 -0
- data/spec/sync_helper_spec.rb +157 -0
- data/spec/sync_runner_spec.rb +78 -0
- data/spec/syncers_spec.rb +171 -0
- data/spec/table_scan_helper_spec.rb +29 -0
- data/spec/table_scan_spec.rb +49 -0
- data/spec/table_sorter_spec.rb +31 -0
- data/spec/table_spec_resolver_spec.rb +102 -0
- data/spec/table_sync_spec.rb +84 -0
- data/spec/trigger_mode_switcher_spec.rb +83 -0
- data/spec/two_way_replicator_spec.rb +551 -0
- data/spec/two_way_syncer_spec.rb +256 -0
- data/spec/type_casting_cursor_spec.rb +50 -0
- data/spec/uninstall_runner_spec.rb +86 -0
- data/tasks/database.rake +439 -0
- data/tasks/deployment.rake +29 -0
- data/tasks/environment.rake +9 -0
- data/tasks/java.rake +37 -0
- data/tasks/redmine_test.rake +47 -0
- data/tasks/rspec.rake +68 -0
- data/tasks/rubyrep.tailor +18 -0
- data/tasks/stats.rake +19 -0
- data/tasks/task_helper.rb +20 -0
- data.tar.gz.sig +0 -0
- metadata +243 -0
- 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
|