rubyrep 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +137 -0
  4. data/README.txt +37 -0
  5. data/Rakefile +30 -0
  6. data/bin/rubyrep +8 -0
  7. data/config/hoe.rb +72 -0
  8. data/config/mysql_config.rb +25 -0
  9. data/config/postgres_config.rb +21 -0
  10. data/config/proxied_test_config.rb +14 -0
  11. data/config/redmine_config.rb +17 -0
  12. data/config/rep_config.rb +20 -0
  13. data/config/requirements.rb +32 -0
  14. data/config/test_config.rb +20 -0
  15. data/lib/rubyrep/base_runner.rb +195 -0
  16. data/lib/rubyrep/command_runner.rb +144 -0
  17. data/lib/rubyrep/committers/buffered_committer.rb +140 -0
  18. data/lib/rubyrep/committers/committers.rb +146 -0
  19. data/lib/rubyrep/configuration.rb +240 -0
  20. data/lib/rubyrep/connection_extenders/connection_extenders.rb +133 -0
  21. data/lib/rubyrep/connection_extenders/jdbc_extender.rb +284 -0
  22. data/lib/rubyrep/connection_extenders/mysql_extender.rb +168 -0
  23. data/lib/rubyrep/connection_extenders/postgresql_extender.rb +261 -0
  24. data/lib/rubyrep/database_proxy.rb +52 -0
  25. data/lib/rubyrep/direct_table_scan.rb +75 -0
  26. data/lib/rubyrep/generate_runner.rb +105 -0
  27. data/lib/rubyrep/initializer.rb +39 -0
  28. data/lib/rubyrep/logged_change.rb +326 -0
  29. data/lib/rubyrep/proxied_table_scan.rb +171 -0
  30. data/lib/rubyrep/proxy_block_cursor.rb +145 -0
  31. data/lib/rubyrep/proxy_connection.rb +318 -0
  32. data/lib/rubyrep/proxy_cursor.rb +44 -0
  33. data/lib/rubyrep/proxy_row_cursor.rb +43 -0
  34. data/lib/rubyrep/proxy_runner.rb +89 -0
  35. data/lib/rubyrep/replication_difference.rb +91 -0
  36. data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
  37. data/lib/rubyrep/replication_extenders/postgresql_replication.rb +204 -0
  38. data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
  39. data/lib/rubyrep/replication_helper.rb +104 -0
  40. data/lib/rubyrep/replication_initializer.rb +307 -0
  41. data/lib/rubyrep/replication_run.rb +48 -0
  42. data/lib/rubyrep/replication_runner.rb +138 -0
  43. data/lib/rubyrep/replicators/replicators.rb +37 -0
  44. data/lib/rubyrep/replicators/two_way_replicator.rb +334 -0
  45. data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
  46. data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
  47. data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
  48. data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
  49. data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
  50. data/lib/rubyrep/scan_runner.rb +25 -0
  51. data/lib/rubyrep/session.rb +177 -0
  52. data/lib/rubyrep/sync_helper.rb +111 -0
  53. data/lib/rubyrep/sync_runner.rb +31 -0
  54. data/lib/rubyrep/syncers/syncers.rb +112 -0
  55. data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
  56. data/lib/rubyrep/table_scan.rb +54 -0
  57. data/lib/rubyrep/table_scan_helper.rb +38 -0
  58. data/lib/rubyrep/table_sorter.rb +70 -0
  59. data/lib/rubyrep/table_spec_resolver.rb +136 -0
  60. data/lib/rubyrep/table_sync.rb +68 -0
  61. data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
  62. data/lib/rubyrep/type_casting_cursor.rb +31 -0
  63. data/lib/rubyrep/uninstall_runner.rb +92 -0
  64. data/lib/rubyrep/version.rb +9 -0
  65. data/lib/rubyrep.rb +68 -0
  66. data/script/destroy +14 -0
  67. data/script/generate +14 -0
  68. data/script/txt2html +74 -0
  69. data/setup.rb +1585 -0
  70. data/sims/performance/big_rep_spec.rb +100 -0
  71. data/sims/performance/big_scan_spec.rb +57 -0
  72. data/sims/performance/big_sync_spec.rb +141 -0
  73. data/sims/performance/performance.rake +228 -0
  74. data/sims/sim_helper.rb +24 -0
  75. data/spec/base_runner_spec.rb +218 -0
  76. data/spec/buffered_committer_spec.rb +271 -0
  77. data/spec/command_runner_spec.rb +145 -0
  78. data/spec/committers_spec.rb +174 -0
  79. data/spec/configuration_spec.rb +198 -0
  80. data/spec/connection_extender_interface_spec.rb +138 -0
  81. data/spec/connection_extenders_registration_spec.rb +129 -0
  82. data/spec/database_proxy_spec.rb +48 -0
  83. data/spec/database_rake_spec.rb +40 -0
  84. data/spec/db_specific_connection_extenders_spec.rb +34 -0
  85. data/spec/db_specific_replication_extenders_spec.rb +38 -0
  86. data/spec/direct_table_scan_spec.rb +61 -0
  87. data/spec/generate_runner_spec.rb +84 -0
  88. data/spec/initializer_spec.rb +46 -0
  89. data/spec/logged_change_spec.rb +480 -0
  90. data/spec/postgresql_replication_spec.rb +48 -0
  91. data/spec/postgresql_support_spec.rb +57 -0
  92. data/spec/progress_bar_spec.rb +77 -0
  93. data/spec/proxied_table_scan_spec.rb +151 -0
  94. data/spec/proxy_block_cursor_spec.rb +197 -0
  95. data/spec/proxy_connection_spec.rb +399 -0
  96. data/spec/proxy_cursor_spec.rb +56 -0
  97. data/spec/proxy_row_cursor_spec.rb +66 -0
  98. data/spec/proxy_runner_spec.rb +70 -0
  99. data/spec/replication_difference_spec.rb +160 -0
  100. data/spec/replication_extender_interface_spec.rb +365 -0
  101. data/spec/replication_extenders_spec.rb +32 -0
  102. data/spec/replication_helper_spec.rb +121 -0
  103. data/spec/replication_initializer_spec.rb +477 -0
  104. data/spec/replication_run_spec.rb +166 -0
  105. data/spec/replication_runner_spec.rb +213 -0
  106. data/spec/replicators_spec.rb +31 -0
  107. data/spec/rubyrep_spec.rb +8 -0
  108. data/spec/scan_detail_reporter_spec.rb +119 -0
  109. data/spec/scan_progress_printers_spec.rb +68 -0
  110. data/spec/scan_report_printers_spec.rb +67 -0
  111. data/spec/scan_runner_spec.rb +50 -0
  112. data/spec/scan_summary_reporter_spec.rb +61 -0
  113. data/spec/session_spec.rb +212 -0
  114. data/spec/spec.opts +1 -0
  115. data/spec/spec_helper.rb +295 -0
  116. data/spec/sync_helper_spec.rb +157 -0
  117. data/spec/sync_runner_spec.rb +78 -0
  118. data/spec/syncers_spec.rb +171 -0
  119. data/spec/table_scan_helper_spec.rb +29 -0
  120. data/spec/table_scan_spec.rb +49 -0
  121. data/spec/table_sorter_spec.rb +31 -0
  122. data/spec/table_spec_resolver_spec.rb +102 -0
  123. data/spec/table_sync_spec.rb +84 -0
  124. data/spec/trigger_mode_switcher_spec.rb +83 -0
  125. data/spec/two_way_replicator_spec.rb +551 -0
  126. data/spec/two_way_syncer_spec.rb +256 -0
  127. data/spec/type_casting_cursor_spec.rb +50 -0
  128. data/spec/uninstall_runner_spec.rb +86 -0
  129. data/tasks/database.rake +439 -0
  130. data/tasks/deployment.rake +29 -0
  131. data/tasks/environment.rake +9 -0
  132. data/tasks/java.rake +37 -0
  133. data/tasks/redmine_test.rake +47 -0
  134. data/tasks/rspec.rake +68 -0
  135. data/tasks/rubyrep.tailor +18 -0
  136. data/tasks/stats.rake +19 -0
  137. data/tasks/task_helper.rb +20 -0
  138. data.tar.gz.sig +0 -0
  139. metadata +243 -0
  140. metadata.gz.sig +0 -0
@@ -0,0 +1,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