rubyrep 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,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