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,477 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ReplicationInitializer do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
after(:each) do
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "initializer should store the session" do
|
|
14
|
+
session = Session.new
|
|
15
|
+
initializer = ReplicationInitializer.new session
|
|
16
|
+
initializer.session.should == session
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "options should return the table specific options if table is given" do
|
|
20
|
+
session = Session.new deep_copy(Initializer.configuration)
|
|
21
|
+
initializer = ReplicationInitializer.new session
|
|
22
|
+
session.configuration.should_receive(:options_for_table).
|
|
23
|
+
with('my_table').
|
|
24
|
+
and_return(:dummy_options)
|
|
25
|
+
initializer.options('my_table').should == :dummy_options
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "options should return the general options if no table is given" do
|
|
29
|
+
session = Session.new deep_copy(Initializer.configuration)
|
|
30
|
+
initializer = ReplicationInitializer.new session
|
|
31
|
+
session.configuration.should_receive(:options).
|
|
32
|
+
and_return(:dummy_options)
|
|
33
|
+
initializer.options.should == :dummy_options
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "create_trigger should create a working trigger" do
|
|
37
|
+
session = nil
|
|
38
|
+
begin
|
|
39
|
+
session = Session.new
|
|
40
|
+
session.left.begin_db_transaction
|
|
41
|
+
initializer = ReplicationInitializer.new(session)
|
|
42
|
+
initializer.create_trigger(:left, 'trigger_test')
|
|
43
|
+
|
|
44
|
+
session.left.insert_record 'trigger_test', {
|
|
45
|
+
'first_id' => 1,
|
|
46
|
+
'second_id' => 2,
|
|
47
|
+
'name' => 'bla'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
row = session.left.select_one("select * from rr_pending_changes")
|
|
51
|
+
row.delete 'id'
|
|
52
|
+
row.delete 'change_time'
|
|
53
|
+
row.should == {
|
|
54
|
+
'change_table' => 'trigger_test',
|
|
55
|
+
'change_key' => 'first_id|1|second_id|2',
|
|
56
|
+
'change_new_key' => nil,
|
|
57
|
+
'change_type' => 'I'
|
|
58
|
+
}
|
|
59
|
+
ensure
|
|
60
|
+
session.left.execute 'delete from trigger_test' if session
|
|
61
|
+
session.left.execute 'delete from rr_pending_changes' if session
|
|
62
|
+
session.left.rollback_db_transaction if session
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "trigger_exists? and drop_trigger should work correctly" do
|
|
67
|
+
session = nil
|
|
68
|
+
begin
|
|
69
|
+
session = Session.new
|
|
70
|
+
initializer = ReplicationInitializer.new(session)
|
|
71
|
+
if initializer.trigger_exists?(:left, 'trigger_test')
|
|
72
|
+
initializer.drop_trigger(:left, 'trigger_test')
|
|
73
|
+
end
|
|
74
|
+
session.left.begin_db_transaction
|
|
75
|
+
|
|
76
|
+
initializer.create_trigger :left, 'trigger_test'
|
|
77
|
+
initializer.trigger_exists?(:left, 'trigger_test').
|
|
78
|
+
should be_true
|
|
79
|
+
initializer.drop_trigger(:left, 'trigger_test')
|
|
80
|
+
initializer.trigger_exists?(:left, 'trigger_test').
|
|
81
|
+
should be_false
|
|
82
|
+
ensure
|
|
83
|
+
session.left.rollback_db_transaction if session
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "ensure_sequence_setup should not do anything if :adjust_sequences option is not given" do
|
|
88
|
+
config = deep_copy(Initializer.configuration)
|
|
89
|
+
config.add_table_options 'sequence_test', :adjust_sequences => false
|
|
90
|
+
session = Session.new(config)
|
|
91
|
+
initializer = ReplicationInitializer.new(session)
|
|
92
|
+
|
|
93
|
+
session.left.should_not_receive(:update_sequences)
|
|
94
|
+
session.right.should_not_receive(:update_sequences)
|
|
95
|
+
|
|
96
|
+
table_pair = {:left => 'sequence_test', :right => 'sequence_test'}
|
|
97
|
+
initializer.ensure_sequence_setup table_pair, 3, 2, 2
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "ensure_sequence_setup should ensure that a table's auto generated ID values have the correct increment and offset" do
|
|
101
|
+
session = nil
|
|
102
|
+
begin
|
|
103
|
+
session = Session.new
|
|
104
|
+
initializer = ReplicationInitializer.new(session)
|
|
105
|
+
session.left.begin_db_transaction
|
|
106
|
+
session.right.begin_db_transaction
|
|
107
|
+
|
|
108
|
+
session.left.execute "delete from sequence_test"
|
|
109
|
+
session.right.execute "delete from sequence_test"
|
|
110
|
+
|
|
111
|
+
# Note:
|
|
112
|
+
# Calling ensure_sequence_setup twice with different values to ensure that
|
|
113
|
+
# it is actually does something.
|
|
114
|
+
|
|
115
|
+
table_pair = {:left => 'sequence_test', :right => 'sequence_test'}
|
|
116
|
+
|
|
117
|
+
initializer.ensure_sequence_setup table_pair, 3, 2, 2
|
|
118
|
+
initializer.ensure_sequence_setup table_pair, 5, 2, 1
|
|
119
|
+
id1, id2 = get_example_sequence_values(session)
|
|
120
|
+
(id2 - id1).should == 5
|
|
121
|
+
(id1 % 5).should == 2
|
|
122
|
+
ensure
|
|
123
|
+
[:left, :right].each do |database|
|
|
124
|
+
initializer.clear_sequence_setup database, 'sequence_test' if session
|
|
125
|
+
session.send(database).execute "delete from sequence_test" if session
|
|
126
|
+
session.send(database).rollback_db_transaction if session
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "clear_sequence_setup should not do anything if :adjust_sequences option is not given" do
|
|
132
|
+
config = deep_copy(Initializer.configuration)
|
|
133
|
+
config.add_table_options 'sequence_test', :adjust_sequences => false
|
|
134
|
+
session = Session.new(config)
|
|
135
|
+
initializer = ReplicationInitializer.new(session)
|
|
136
|
+
|
|
137
|
+
session.left.should_not_receive(:clear_sequence_setup)
|
|
138
|
+
|
|
139
|
+
initializer.clear_sequence_setup :left, 'sequence_test'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "clear_sequence_setup should remove custom sequence settings" do
|
|
143
|
+
session = nil
|
|
144
|
+
begin
|
|
145
|
+
session = Session.new
|
|
146
|
+
initializer = ReplicationInitializer.new(session)
|
|
147
|
+
session.left.begin_db_transaction
|
|
148
|
+
session.right.begin_db_transaction
|
|
149
|
+
table_pair = {:left => 'sequence_test', :right => 'sequence_test'}
|
|
150
|
+
initializer.ensure_sequence_setup table_pair, 5, 2, 2
|
|
151
|
+
initializer.clear_sequence_setup :left, 'sequence_test'
|
|
152
|
+
id1, id2 = get_example_sequence_values(session)
|
|
153
|
+
(id2 - id1).should == 1
|
|
154
|
+
ensure
|
|
155
|
+
[:left, :right].each do |database|
|
|
156
|
+
initializer.clear_sequence_setup database, 'sequence_test' if session
|
|
157
|
+
session.send(database).execute "delete from sequence_test" if session
|
|
158
|
+
session.send(database).rollback_db_transaction if session
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "change_log_exists? should return true if replication log exists" do
|
|
164
|
+
config = deep_copy(standard_config)
|
|
165
|
+
initializer = ReplicationInitializer.new(Session.new(config))
|
|
166
|
+
initializer.change_log_exists?(:left).should be_true
|
|
167
|
+
config.options[:rep_prefix] = 'r2'
|
|
168
|
+
initializer = ReplicationInitializer.new(Session.new(config))
|
|
169
|
+
initializer.change_log_exists?(:left).should be_false
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "event_log_exists? should return true if event log exists" do
|
|
173
|
+
config = deep_copy(standard_config)
|
|
174
|
+
initializer = ReplicationInitializer.new(Session.new(config))
|
|
175
|
+
initializer.event_log_exists?.should be_true
|
|
176
|
+
config.options[:rep_prefix] = 'r2'
|
|
177
|
+
initializer = ReplicationInitializer.new(Session.new(config))
|
|
178
|
+
initializer.event_log_exists?.should be_false
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "create_event_log / drop_event_log should create / drop the event log" do
|
|
182
|
+
config = deep_copy(standard_config)
|
|
183
|
+
config.options[:rep_prefix] = 'r2'
|
|
184
|
+
session = Session.new(config)
|
|
185
|
+
initializer = ReplicationInitializer.new(session)
|
|
186
|
+
initializer.drop_logged_events if initializer.event_log_exists?
|
|
187
|
+
|
|
188
|
+
$stderr.stub! :write
|
|
189
|
+
initializer.event_log_exists?.should be_false
|
|
190
|
+
initializer.create_event_log
|
|
191
|
+
initializer.event_log_exists?.should be_true
|
|
192
|
+
|
|
193
|
+
# verify that replication log has 8 byte, auto-generating primary key
|
|
194
|
+
session.left.insert_record 'r2_logged_events', {'id' => 1e18.to_i, 'change_key' => 'blub'}
|
|
195
|
+
session.left.select_one("select id from r2_logged_events where change_key = 'blub'")['id'].
|
|
196
|
+
to_i.should == 1e18.to_i
|
|
197
|
+
|
|
198
|
+
initializer.drop_event_log
|
|
199
|
+
initializer.event_log_exists?.should be_false
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it "create_change_log / drop_change_log should create / drop the replication log" do
|
|
203
|
+
config = deep_copy(standard_config)
|
|
204
|
+
config.options[:rep_prefix] = 'r2'
|
|
205
|
+
session = Session.new(config)
|
|
206
|
+
initializer = ReplicationInitializer.new(session)
|
|
207
|
+
initializer.drop_change_log(:left) if initializer.change_log_exists?(:left)
|
|
208
|
+
|
|
209
|
+
$stderr.stub! :write
|
|
210
|
+
initializer.change_log_exists?(:left).should be_false
|
|
211
|
+
initializer.create_change_log(:left)
|
|
212
|
+
initializer.change_log_exists?(:left).should be_true
|
|
213
|
+
|
|
214
|
+
# verify that replication log has 8 byte, auto-generating primary key
|
|
215
|
+
session.left.insert_record 'r2_pending_changes', {'change_key' => 'bla'}
|
|
216
|
+
session.left.select_one("select id from r2_pending_changes where change_key = 'bla'")['id'].
|
|
217
|
+
to_i.should > 0
|
|
218
|
+
session.left.insert_record 'r2_pending_changes', {'id' => 1e18.to_i, 'change_key' => 'blub'}
|
|
219
|
+
session.left.select_one("select id from r2_pending_changes where change_key = 'blub'")['id'].
|
|
220
|
+
to_i.should == 1e18.to_i
|
|
221
|
+
|
|
222
|
+
initializer.drop_change_log(:left)
|
|
223
|
+
initializer.change_log_exists?(:left).should be_false
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "ensure_activity_markers should not create the tables if they already exist" do
|
|
227
|
+
session = Session.new
|
|
228
|
+
initializer = ReplicationInitializer.new(session)
|
|
229
|
+
session.left.should_not_receive(:create_table)
|
|
230
|
+
initializer.ensure_activity_markers
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "ensure_activity_markers should create the marker tables" do
|
|
234
|
+
begin
|
|
235
|
+
config = deep_copy(standard_config)
|
|
236
|
+
config.options[:rep_prefix] = 'rx'
|
|
237
|
+
session = Session.new(config)
|
|
238
|
+
initializer = ReplicationInitializer.new(session)
|
|
239
|
+
initializer.ensure_activity_markers
|
|
240
|
+
session.left.tables.include?('rx_running_flags').should be_true
|
|
241
|
+
session.right.tables.include?('rx_running_flags').should be_true
|
|
242
|
+
|
|
243
|
+
# right columns?
|
|
244
|
+
columns = session.left.columns('rx_running_flags')
|
|
245
|
+
columns.size.should == 1
|
|
246
|
+
columns[0].name.should == 'active'
|
|
247
|
+
ensure
|
|
248
|
+
if session
|
|
249
|
+
session.left.drop_table 'rx_running_flags'
|
|
250
|
+
session.right.drop_table 'rx_running_flags'
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "ensure_infrastructure should not create the infrastructure tables if they already exist" do
|
|
256
|
+
session = Session.new
|
|
257
|
+
initializer = ReplicationInitializer.new(session)
|
|
258
|
+
session.left.should_not_receive(:create_table)
|
|
259
|
+
initializer.ensure_infrastructure
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "drop_change_logs should drop the change_log tables" do
|
|
263
|
+
session = Session.new
|
|
264
|
+
initializer = ReplicationInitializer.new session
|
|
265
|
+
initializer.should_receive(:drop_change_log).with(:left)
|
|
266
|
+
initializer.should_receive(:drop_change_log).with(:right)
|
|
267
|
+
|
|
268
|
+
initializer.drop_change_logs
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "drop_change_logs should not do anything if change_log tables do not exist" do
|
|
272
|
+
config = deep_copy(standard_config)
|
|
273
|
+
config.options[:rep_prefix] = 'rx'
|
|
274
|
+
session = Session.new(config)
|
|
275
|
+
initializer = ReplicationInitializer.new session
|
|
276
|
+
initializer.should_not_receive(:drop_change_log).with(:left)
|
|
277
|
+
initializer.should_not_receive(:drop_change_log).with(:right)
|
|
278
|
+
|
|
279
|
+
initializer.drop_change_logs
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it "drop_activity_markers should drop the activity_marker tables" do
|
|
283
|
+
session = Session.new
|
|
284
|
+
initializer = ReplicationInitializer.new session
|
|
285
|
+
session.left.should_receive(:drop_table).with('rr_running_flags')
|
|
286
|
+
session.right.should_receive(:drop_table).with('rr_running_flags')
|
|
287
|
+
|
|
288
|
+
initializer.drop_activity_markers
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
it "drop_activity_markers should not do anything if the activity_marker tables do not exist" do
|
|
292
|
+
config = deep_copy(standard_config)
|
|
293
|
+
config.options[:rep_prefix] = 'rx'
|
|
294
|
+
session = Session.new(config)
|
|
295
|
+
initializer = ReplicationInitializer.new session
|
|
296
|
+
session.left.should_not_receive(:drop_table).with('rr_running_flags')
|
|
297
|
+
session.right.should_not_receive(:drop_table).with('rr_running_flags')
|
|
298
|
+
|
|
299
|
+
initializer.drop_change_logs
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it "drop_infrastructure should drop all infrastructure tables" do
|
|
303
|
+
session = Session.new
|
|
304
|
+
initializer = ReplicationInitializer.new session
|
|
305
|
+
initializer.should_receive(:drop_event_log)
|
|
306
|
+
initializer.should_receive(:drop_change_logs)
|
|
307
|
+
initializer.should_receive(:drop_activity_markers)
|
|
308
|
+
|
|
309
|
+
initializer.drop_infrastructure
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "ensure_change_logs should create the change_log tables" do
|
|
313
|
+
session = nil
|
|
314
|
+
begin
|
|
315
|
+
config = deep_copy(standard_config)
|
|
316
|
+
config.options[:rep_prefix] = 'rx'
|
|
317
|
+
session = Session.new(config)
|
|
318
|
+
initializer = ReplicationInitializer.new(session)
|
|
319
|
+
initializer.ensure_change_logs
|
|
320
|
+
ensure
|
|
321
|
+
if session
|
|
322
|
+
session.left.drop_table 'rx_pending_changes'
|
|
323
|
+
session.right.drop_table 'rx_pending_changes'
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "ensure_change_logs should do nothing if the change_log tables already exist" do
|
|
329
|
+
session = Session.new
|
|
330
|
+
initializer = ReplicationInitializer.new session
|
|
331
|
+
initializer.should_not_receive(:create_change_log)
|
|
332
|
+
|
|
333
|
+
initializer.ensure_change_logs
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it "ensure_event_log should create the event_log table" do
|
|
337
|
+
session = nil
|
|
338
|
+
begin
|
|
339
|
+
config = deep_copy(standard_config)
|
|
340
|
+
config.options[:rep_prefix] = 'rx'
|
|
341
|
+
session = Session.new(config)
|
|
342
|
+
initializer = ReplicationInitializer.new(session)
|
|
343
|
+
initializer.ensure_event_log
|
|
344
|
+
ensure
|
|
345
|
+
session.left.drop_table 'rx_logged_events' if session
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it "ensure_event_log should do nothing if the event_log table already exist" do
|
|
350
|
+
session = Session.new
|
|
351
|
+
initializer = ReplicationInitializer.new session
|
|
352
|
+
initializer.should_not_receive(:create_event_log)
|
|
353
|
+
|
|
354
|
+
initializer.ensure_event_log
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it "ensure_infrastructure should create the infrastructure tables" do
|
|
358
|
+
session = Session.new
|
|
359
|
+
initializer = ReplicationInitializer.new(session)
|
|
360
|
+
initializer.should_receive :ensure_activity_markers
|
|
361
|
+
initializer.should_receive :ensure_change_logs
|
|
362
|
+
initializer.should_receive :ensure_event_log
|
|
363
|
+
initializer.ensure_infrastructure
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
it "exclude_ruby_rep_tables should exclude the correct system tables" do
|
|
367
|
+
config = deep_copy(standard_config)
|
|
368
|
+
initializer = ReplicationInitializer.new(Session.new(config))
|
|
369
|
+
initializer.exclude_rubyrep_tables
|
|
370
|
+
initializer.session.configuration.excluded_table_specs.include?(/^rr_.*/).should be_true
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
it "restore_unconfigured_tables should remove triggers and sequences setups of unconfigured tables" do
|
|
374
|
+
session = Session.new
|
|
375
|
+
initializer = ReplicationInitializer.new session
|
|
376
|
+
begin
|
|
377
|
+
['scanner_left_records_only', 'scanner_records'].each do |table|
|
|
378
|
+
initializer.create_trigger(:left, table)
|
|
379
|
+
initializer.create_trigger(:right, table)
|
|
380
|
+
initializer.ensure_sequence_setup(
|
|
381
|
+
{:left => table, :right => table},
|
|
382
|
+
2, 0, 1
|
|
383
|
+
)
|
|
384
|
+
session.right.insert_record table, {'id' => 100, 'name' => 'bla'}
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# verify that the unconfigured tables are restored and pending changes deleted
|
|
388
|
+
initializer.restore_unconfigured_tables
|
|
389
|
+
initializer.trigger_exists?(:right, 'scanner_records').should be_false
|
|
390
|
+
session.right.sequence_values('rr', 'scanner_records').values[0][:increment].should == 1
|
|
391
|
+
session.right.select_one("select * from rr_pending_changes where change_table = 'scanner_records'").should be_nil
|
|
392
|
+
|
|
393
|
+
# verify that the configured tables are not touched
|
|
394
|
+
initializer.trigger_exists?(:right, 'scanner_left_records_only').should be_true
|
|
395
|
+
session.right.sequence_values('rr', 'scanner_left_records_only').values[0][:increment].should == 2
|
|
396
|
+
session.right.select_one("select * from rr_pending_changes where change_table = 'scanner_left_records_only'").should_not be_nil
|
|
397
|
+
ensure
|
|
398
|
+
['scanner_left_records_only', 'scanner_records'].each do |table|
|
|
399
|
+
[:left, :right].each do |database|
|
|
400
|
+
if initializer.trigger_exists?(database, table)
|
|
401
|
+
initializer.drop_trigger(database, table)
|
|
402
|
+
end
|
|
403
|
+
initializer.clear_sequence_setup database, table
|
|
404
|
+
end
|
|
405
|
+
session.right.delete_record table, {'id' => 100}
|
|
406
|
+
end
|
|
407
|
+
session.right.execute "delete from rr_pending_changes"
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
it "prepare_replication should prepare the replication" do
|
|
412
|
+
session = nil
|
|
413
|
+
initializer = nil
|
|
414
|
+
org_stdout = $stdout
|
|
415
|
+
|
|
416
|
+
config = deep_copy(standard_config)
|
|
417
|
+
config.options[:committer] = :buffered_commit
|
|
418
|
+
config.options[:use_ansi] = false
|
|
419
|
+
config.include_tables 'rr_pending_changes' # added to verify that it is ignored
|
|
420
|
+
|
|
421
|
+
session = Session.new(config)
|
|
422
|
+
|
|
423
|
+
$stdout = StringIO.new
|
|
424
|
+
begin
|
|
425
|
+
initializer = ReplicationInitializer.new(session)
|
|
426
|
+
initializer.should_receive(:ensure_infrastructure).any_number_of_times
|
|
427
|
+
initializer.should_receive(:restore_unconfigured_tables).any_number_of_times
|
|
428
|
+
initializer.prepare_replication
|
|
429
|
+
# verify sequences have been setup
|
|
430
|
+
session.left.sequence_values('rr','scanner_left_records_only').values[0][:increment].should == 2
|
|
431
|
+
session.right.sequence_values('rr','scanner_left_records_only').values[0][:increment].should == 2
|
|
432
|
+
|
|
433
|
+
# verify table was synced
|
|
434
|
+
left_records = session.left.select_all("select * from scanner_left_records_only order by id")
|
|
435
|
+
right_records = session.left.select_all("select * from scanner_left_records_only order by id")
|
|
436
|
+
left_records.should == right_records
|
|
437
|
+
|
|
438
|
+
# verify rubyrep activity is _not_ logged
|
|
439
|
+
session.right.select_all("select * from rr_pending_changes").should be_empty
|
|
440
|
+
|
|
441
|
+
# verify other data changes are logged
|
|
442
|
+
initializer.trigger_exists?(:left, 'scanner_left_records_only').should be_true
|
|
443
|
+
session.left.insert_record 'scanner_left_records_only', {'id' => 10, 'name' => 'bla'}
|
|
444
|
+
changes = session.left.select_all("select change_key from rr_pending_changes")
|
|
445
|
+
changes.size.should == 1
|
|
446
|
+
changes[0]['change_key'].should == 'id|10'
|
|
447
|
+
|
|
448
|
+
# verify that the 'rr_pending_changes' table was not touched
|
|
449
|
+
initializer.trigger_exists?(:left, 'rr_pending_changes').should be_false
|
|
450
|
+
|
|
451
|
+
# verify that syncing is done only for unsynced tables
|
|
452
|
+
SyncRunner.should_not_receive(:new)
|
|
453
|
+
initializer.prepare_replication
|
|
454
|
+
|
|
455
|
+
ensure
|
|
456
|
+
$stdout = org_stdout
|
|
457
|
+
if session
|
|
458
|
+
session.left.execute "delete from scanner_left_records_only where id = 10"
|
|
459
|
+
session.right.execute "delete from scanner_left_records_only"
|
|
460
|
+
[:left, :right].each do |database|
|
|
461
|
+
session.send(database).execute "delete from rr_pending_changes"
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
if initializer
|
|
465
|
+
[:left, :right].each do |database|
|
|
466
|
+
initializer.clear_sequence_setup database, 'scanner_left_records_only'
|
|
467
|
+
initializer.clear_sequence_setup database, 'table_with_manual_key'
|
|
468
|
+
['scanner_left_records_only', 'table_with_manual_key'].each do |table|
|
|
469
|
+
if initializer.trigger_exists?(database, table)
|
|
470
|
+
initializer.drop_trigger database, table
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ReplicationRun do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initialize should store the provided session" do
|
|
11
|
+
session = Session.new
|
|
12
|
+
run = ReplicationRun.new session
|
|
13
|
+
run.session.should == session
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "helper should return the correctly initialized replication helper" do
|
|
17
|
+
run = ReplicationRun.new Session.new
|
|
18
|
+
run.helper.should be_an_instance_of(ReplicationHelper)
|
|
19
|
+
run.helper.replication_run.should == run
|
|
20
|
+
run.helper.should == run.helper # ensure the helper is created only once
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "replicator should return the configured replicator" do
|
|
24
|
+
session = Session.new
|
|
25
|
+
run = ReplicationRun.new session
|
|
26
|
+
run.replicator.
|
|
27
|
+
should be_an_instance_of(Replicators.replicators[session.configuration.options[:replicator]])
|
|
28
|
+
run.replicator.should == run.replicator # should only create the replicator once
|
|
29
|
+
run.replicator.rep_helper.should == run.helper
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "run should replicate all logged changes" do
|
|
33
|
+
begin
|
|
34
|
+
config = deep_copy(standard_config)
|
|
35
|
+
config.options[:committer] = :never_commit
|
|
36
|
+
|
|
37
|
+
session = Session.new(config)
|
|
38
|
+
|
|
39
|
+
session.left.insert_record 'extender_no_record', {
|
|
40
|
+
'id' => '1',
|
|
41
|
+
'name' => 'bla'
|
|
42
|
+
}
|
|
43
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
44
|
+
'change_table' => 'extender_no_record',
|
|
45
|
+
'change_key' => 'id|1',
|
|
46
|
+
'change_type' => 'I',
|
|
47
|
+
'change_time' => Time.now
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
run = ReplicationRun.new session
|
|
51
|
+
run.run
|
|
52
|
+
|
|
53
|
+
session.right.select_one("select * from extender_no_record").should == {
|
|
54
|
+
'id' => '1',
|
|
55
|
+
'name' => 'bla'
|
|
56
|
+
}
|
|
57
|
+
ensure
|
|
58
|
+
Committers::NeverCommitter.rollback_current_session
|
|
59
|
+
if session
|
|
60
|
+
session.left.execute "delete from extender_no_record"
|
|
61
|
+
session.right.execute "delete from extender_no_record"
|
|
62
|
+
session.left.execute "delete from rr_pending_changes"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "run should only replicate real differences" do
|
|
68
|
+
session = Session.new
|
|
69
|
+
session.left.begin_db_transaction
|
|
70
|
+
session.right.begin_db_transaction
|
|
71
|
+
begin
|
|
72
|
+
|
|
73
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
74
|
+
'change_table' => 'extender_no_record',
|
|
75
|
+
'change_key' => 'id|1',
|
|
76
|
+
'change_type' => 'D',
|
|
77
|
+
'change_time' => Time.now
|
|
78
|
+
}
|
|
79
|
+
session.right.insert_record 'rr_pending_changes', {
|
|
80
|
+
'change_table' => 'extender_no_record',
|
|
81
|
+
'change_key' => 'id|1',
|
|
82
|
+
'change_type' => 'D',
|
|
83
|
+
'change_time' => Time.now
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
run = ReplicationRun.new session
|
|
87
|
+
run.replicator.should_not_receive(:replicate)
|
|
88
|
+
run.run
|
|
89
|
+
|
|
90
|
+
ensure
|
|
91
|
+
session.left.rollback_db_transaction
|
|
92
|
+
session.right.rollback_db_transaction
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "run should log raised exceptions" do
|
|
97
|
+
session = Session.new
|
|
98
|
+
session.left.begin_db_transaction
|
|
99
|
+
session.right.begin_db_transaction
|
|
100
|
+
begin
|
|
101
|
+
|
|
102
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
103
|
+
'change_table' => 'extender_no_record',
|
|
104
|
+
'change_key' => 'id|1',
|
|
105
|
+
'change_type' => 'D',
|
|
106
|
+
'change_time' => Time.now
|
|
107
|
+
}
|
|
108
|
+
run = ReplicationRun.new session
|
|
109
|
+
run.replicator.stub!(:replicate_difference).and_return {raise Exception, 'dummy message'}
|
|
110
|
+
run.run
|
|
111
|
+
|
|
112
|
+
row = session.left.select_one("select * from rr_logged_events")
|
|
113
|
+
row['description'].should == 'dummy message'
|
|
114
|
+
row['long_description'].should =~ /Exception/
|
|
115
|
+
ensure
|
|
116
|
+
session.left.rollback_db_transaction
|
|
117
|
+
session.right.rollback_db_transaction
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "run should not catch exceptions raised during replicator initialization" do
|
|
122
|
+
config = deep_copy(standard_config)
|
|
123
|
+
config.options[:logged_replication_events] = [:invalid_option]
|
|
124
|
+
run = ReplicationRun.new Session.new(config)
|
|
125
|
+
lambda {run.run}.should raise_error(ArgumentError)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "run should process trigger created change log records" do
|
|
129
|
+
begin
|
|
130
|
+
config = deep_copy(standard_config)
|
|
131
|
+
config.options[:committer] = :never_commit
|
|
132
|
+
config.options[:logged_replication_events] = [:all_changes]
|
|
133
|
+
|
|
134
|
+
session = Session.new(config)
|
|
135
|
+
initializer = ReplicationInitializer.new(session)
|
|
136
|
+
initializer.create_trigger :left, 'extender_no_record'
|
|
137
|
+
|
|
138
|
+
session.left.insert_record 'extender_no_record', {
|
|
139
|
+
'id' => '1',
|
|
140
|
+
'name' => 'bla'
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
run = ReplicationRun.new session
|
|
144
|
+
run.run
|
|
145
|
+
|
|
146
|
+
session.right.select_one("select * from extender_no_record").should == {
|
|
147
|
+
'id' => '1',
|
|
148
|
+
'name' => 'bla'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# also verify that event was logged
|
|
152
|
+
row = session.left.select_one("select * from rr_logged_events")
|
|
153
|
+
row['diff_type'].should == 'left'
|
|
154
|
+
row['change_key'].should == '1'
|
|
155
|
+
row['description'].should == 'replicated'
|
|
156
|
+
ensure
|
|
157
|
+
Committers::NeverCommitter.rollback_current_session
|
|
158
|
+
if session
|
|
159
|
+
session.left.execute "delete from extender_no_record"
|
|
160
|
+
session.right.execute "delete from extender_no_record"
|
|
161
|
+
session.left.execute "delete from rr_pending_changes"
|
|
162
|
+
end
|
|
163
|
+
initializer.drop_trigger :left, 'extender_no_record' if initializer
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|