rubyrep 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +18 -0
  5. data/Gemfile.lock +84 -0
  6. data/History.txt +6 -0
  7. data/README.txt +1 -1
  8. data/Rakefile +6 -27
  9. data/bin/rubyrep +1 -1
  10. data/config/mysql_config.rb +2 -2
  11. data/config/postgres_config.rb +5 -3
  12. data/lib/rubyrep/command_runner.rb +1 -1
  13. data/lib/rubyrep/connection_extenders/connection_extenders.rb +30 -44
  14. data/lib/rubyrep/connection_extenders/mysql_extender.rb +23 -1
  15. data/lib/rubyrep/connection_extenders/postgresql_extender.rb +31 -168
  16. data/lib/rubyrep/generate_runner.rb +1 -1
  17. data/lib/rubyrep/logged_change.rb +1 -1
  18. data/lib/rubyrep/proxy_connection.rb +22 -12
  19. data/lib/rubyrep/replication_difference.rb +1 -1
  20. data/lib/rubyrep/replication_extenders/mysql_replication.rb +1 -1
  21. data/lib/rubyrep/replication_helper.rb +1 -1
  22. data/lib/rubyrep/replication_runner.rb +10 -0
  23. data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +1 -1
  24. data/lib/rubyrep/table_spec_resolver.rb +1 -1
  25. data/lib/rubyrep/type_casting_cursor.rb +8 -4
  26. data/lib/rubyrep/version.rb +1 -7
  27. data/lib/rubyrep.rb +4 -3
  28. data/rubyrep +4 -0
  29. data/rubyrep.bat +5 -0
  30. data/rubyrep.gemspec +29 -0
  31. data/sims/performance/big_rep_spec.rb +34 -17
  32. data/sims/performance/performance.rake +11 -31
  33. data/tasks/database.rake +14 -14
  34. data/tasks/java.rake +18 -5
  35. data/tasks/rspec.rake +14 -34
  36. data/tasks/stats.rake +1 -16
  37. metadata +99 -162
  38. data/.gemtest +0 -0
  39. data/config/requirements.rb +0 -32
  40. data/lib/rubyrep/connection_extenders/jdbc_extender.rb +0 -65
  41. data/spec/base_runner_spec.rb +0 -218
  42. data/spec/buffered_committer_spec.rb +0 -274
  43. data/spec/command_runner_spec.rb +0 -145
  44. data/spec/committers_spec.rb +0 -178
  45. data/spec/configuration_spec.rb +0 -203
  46. data/spec/connection_extender_interface_spec.rb +0 -141
  47. data/spec/connection_extenders_registration_spec.rb +0 -164
  48. data/spec/database_proxy_spec.rb +0 -48
  49. data/spec/database_rake_spec.rb +0 -40
  50. data/spec/db_specific_connection_extenders_spec.rb +0 -34
  51. data/spec/db_specific_replication_extenders_spec.rb +0 -38
  52. data/spec/direct_table_scan_spec.rb +0 -61
  53. data/spec/dolphins.jpg +0 -0
  54. data/spec/generate_runner_spec.rb +0 -84
  55. data/spec/initializer_spec.rb +0 -46
  56. data/spec/log_helper_spec.rb +0 -39
  57. data/spec/logged_change_loader_spec.rb +0 -68
  58. data/spec/logged_change_spec.rb +0 -470
  59. data/spec/noisy_connection_spec.rb +0 -78
  60. data/spec/postgresql_replication_spec.rb +0 -48
  61. data/spec/postgresql_schema_support_spec.rb +0 -212
  62. data/spec/postgresql_support_spec.rb +0 -63
  63. data/spec/progress_bar_spec.rb +0 -77
  64. data/spec/proxied_table_scan_spec.rb +0 -151
  65. data/spec/proxy_block_cursor_spec.rb +0 -197
  66. data/spec/proxy_connection_spec.rb +0 -423
  67. data/spec/proxy_cursor_spec.rb +0 -56
  68. data/spec/proxy_row_cursor_spec.rb +0 -66
  69. data/spec/proxy_runner_spec.rb +0 -70
  70. data/spec/replication_difference_spec.rb +0 -161
  71. data/spec/replication_extender_interface_spec.rb +0 -367
  72. data/spec/replication_extenders_spec.rb +0 -32
  73. data/spec/replication_helper_spec.rb +0 -178
  74. data/spec/replication_initializer_spec.rb +0 -509
  75. data/spec/replication_run_spec.rb +0 -443
  76. data/spec/replication_runner_spec.rb +0 -254
  77. data/spec/replicators_spec.rb +0 -36
  78. data/spec/rubyrep_spec.rb +0 -8
  79. data/spec/scan_detail_reporter_spec.rb +0 -119
  80. data/spec/scan_progress_printers_spec.rb +0 -68
  81. data/spec/scan_report_printers_spec.rb +0 -67
  82. data/spec/scan_runner_spec.rb +0 -50
  83. data/spec/scan_summary_reporter_spec.rb +0 -61
  84. data/spec/session_spec.rb +0 -253
  85. data/spec/spec.opts +0 -1
  86. data/spec/spec_helper.rb +0 -305
  87. data/spec/strange_name_support_spec.rb +0 -135
  88. data/spec/sync_helper_spec.rb +0 -169
  89. data/spec/sync_runner_spec.rb +0 -78
  90. data/spec/syncers_spec.rb +0 -171
  91. data/spec/table_scan_helper_spec.rb +0 -36
  92. data/spec/table_scan_spec.rb +0 -49
  93. data/spec/table_sorter_spec.rb +0 -30
  94. data/spec/table_spec_resolver_spec.rb +0 -111
  95. data/spec/table_sync_spec.rb +0 -140
  96. data/spec/task_sweeper_spec.rb +0 -47
  97. data/spec/trigger_mode_switcher_spec.rb +0 -83
  98. data/spec/two_way_replicator_spec.rb +0 -721
  99. data/spec/two_way_syncer_spec.rb +0 -256
  100. data/spec/type_casting_cursor_spec.rb +0 -50
  101. data/spec/uninstall_runner_spec.rb +0 -93
  102. data/tasks/rubyrep.tailor +0 -18
  103. data/tasks/website.rake +0 -19
@@ -1,443 +0,0 @@
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
- sweeper = TaskSweeper.new 1
13
- run = ReplicationRun.new session, sweeper
14
- run.session.should == session
15
- end
16
-
17
- it "install_sweeper should install a task sweeper into the database connections" do
18
- session = Session.new
19
- sweeper = TaskSweeper.new 1
20
- run = ReplicationRun.new session, sweeper
21
- run.install_sweeper
22
-
23
- session.left.sweeper.should == sweeper
24
- session.right.sweeper.should == sweeper
25
- end
26
-
27
- it "helper should return the correctly initialized replication helper" do
28
- run = ReplicationRun.new Session.new, TaskSweeper.new(1)
29
- run.helper.should be_an_instance_of(ReplicationHelper)
30
- run.helper.replication_run.should == run
31
- run.helper.should == run.helper # ensure the helper is created only once
32
- end
33
-
34
- it "replicator should return the configured replicator" do
35
- session = Session.new
36
- run = ReplicationRun.new session, TaskSweeper.new(1)
37
- run.replicator.
38
- should be_an_instance_of(Replicators.replicators[session.configuration.options[:replicator]])
39
- run.replicator.should == run.replicator # should only create the replicator once
40
- run.replicator.rep_helper.should == run.helper
41
- end
42
-
43
- it "event_filtered? should behave correctly" do
44
- begin
45
- config = deep_copy(standard_config)
46
- config.options[:committer] = :never_commit
47
- session = Session.new(config)
48
-
49
- session.left.insert_record 'extender_no_record', {
50
- 'id' => '1',
51
- 'name' => 'bla'
52
- }
53
- session.left.insert_record 'rr_pending_changes', {
54
- 'change_table' => 'extender_no_record',
55
- 'change_key' => 'id|1',
56
- 'change_type' => 'I',
57
- 'change_time' => Time.now
58
- }
59
-
60
- loaders = LoggedChangeLoaders.new(session)
61
- loaders.update
62
- diff = ReplicationDifference.new loaders
63
- diff.load
64
-
65
- # No event filter at all
66
- run = ReplicationRun.new session, TaskSweeper.new(1)
67
- run.event_filtered?(diff).should be_false
68
-
69
- # Event filter that does not handle replication events
70
- session.configuration.options[:event_filter] = Object.new
71
- run = ReplicationRun.new session, TaskSweeper.new(1)
72
- run.event_filtered?(diff).should be_false
73
-
74
- # event_filtered? should signal filtering (i. e. return true) if filter returns false.
75
- filter = Object.new
76
- def filter.before_replicate(table, key, helper, diff)
77
- false
78
- end
79
- session.configuration.options[:event_filter] = filter
80
- run = ReplicationRun.new session, TaskSweeper.new(1)
81
- run.event_filtered?(diff).should be_true
82
-
83
- # event_filtered? should return false if filter returns true.
84
- filter = {}
85
- def filter.before_replicate(table, key, helper, diff)
86
- self[:args] = [table, key, helper, diff]
87
- true
88
- end
89
- session.configuration.options[:event_filter] = filter
90
- run = ReplicationRun.new session, TaskSweeper.new(1)
91
- run.event_filtered?(diff).should be_false
92
- filter[:args].should == ['extender_no_record', {'id' => 1}, run.helper, diff]
93
- ensure
94
- Committers::NeverCommitter.rollback_current_session
95
- if session
96
- session.left.execute "delete from extender_no_record"
97
- session.right.execute "delete from extender_no_record"
98
- session.left.execute "delete from rr_pending_changes"
99
- end
100
- end
101
- end
102
-
103
- it "run should replicate all logged changes" do
104
- begin
105
- config = deep_copy(standard_config)
106
- config.options[:committer] = :never_commit
107
-
108
- session = Session.new(config)
109
-
110
- session.left.insert_record 'extender_no_record', {
111
- 'id' => '1',
112
- 'name' => 'bla'
113
- }
114
- session.left.insert_record 'rr_pending_changes', {
115
- 'change_table' => 'extender_no_record',
116
- 'change_key' => 'id|1',
117
- 'change_type' => 'I',
118
- 'change_time' => Time.now
119
- }
120
-
121
- run = ReplicationRun.new session, TaskSweeper.new(1)
122
- run.run
123
-
124
- session.right.select_record(:table => "extender_no_record").should == {
125
- 'id' => 1,
126
- 'name' => 'bla'
127
- }
128
- ensure
129
- Committers::NeverCommitter.rollback_current_session
130
- if session
131
- session.left.execute "delete from extender_no_record"
132
- session.right.execute "delete from extender_no_record"
133
- session.left.execute "delete from rr_pending_changes"
134
- end
135
- end
136
- end
137
-
138
- it "run should replication records with foreign key constraints" do
139
- begin
140
- config = deep_copy(standard_config)
141
- config.options[:committer] = :never_commit
142
-
143
- session = Session.new(config)
144
-
145
- session.left.insert_record 'referencing_table', {
146
- 'id' => '5',
147
- }
148
- session.left.insert_record 'rr_pending_changes', {
149
- 'change_table' => 'referencing_table',
150
- 'change_key' => 'id|5',
151
- 'change_type' => 'I',
152
- 'change_time' => Time.now
153
- }
154
-
155
- session.left.insert_record 'referenced_table2', {
156
- 'id' => '6',
157
- }
158
- session.left.insert_record 'rr_pending_changes', {
159
- 'change_table' => 'referenced_table2',
160
- 'change_key' => 'id|6',
161
- 'change_type' => 'I',
162
- 'change_time' => Time.now
163
- }
164
-
165
- session.left.update_record 'referencing_table', {
166
- 'id' => 5,
167
- 'third_fk' => '6'
168
- }
169
- session.left.insert_record 'rr_pending_changes', {
170
- 'change_table' => 'referencing_table',
171
- 'change_key' => 'id|5',
172
- 'change_new_key' => 'id|5',
173
- 'change_type' => 'U',
174
- 'change_time' => Time.now
175
- }
176
-
177
- run = ReplicationRun.new session, TaskSweeper.new(1)
178
- run.run
179
-
180
- session.right.select_record(:table => "referencing_table", :from => {'id' => 5}).should == {
181
- 'id' => 5,
182
- 'first_fk' => nil,
183
- 'second_fk' => nil,
184
- 'third_fk' => 6
185
- }
186
- ensure
187
- Committers::NeverCommitter.rollback_current_session
188
- if session
189
- session.left.execute "delete from referencing_table where id = 5"
190
- session.left.execute "delete from referenced_table2 where id = 6"
191
-
192
- session.right.execute "delete from referencing_table where id = 5"
193
- session.right.execute "delete from referenced_table2 where id = 6"
194
-
195
- session.left.execute "delete from rr_pending_changes"
196
- end
197
- end
198
- end
199
-
200
- it "run should not replicate filtered changes" do
201
- begin
202
- config = deep_copy(standard_config)
203
- config.options[:committer] = :never_commit
204
-
205
- filter = Object.new
206
- def filter.before_replicate(table, key, helper, diff)
207
- key['id'] != 1
208
- end
209
- config.options[:event_filter] = filter
210
-
211
- session = Session.new(config)
212
-
213
- session.left.insert_record 'extender_no_record', {
214
- 'id' => '1',
215
- 'name' => 'bla'
216
- }
217
- session.left.insert_record 'extender_no_record', {
218
- 'id' => '2',
219
- 'name' => 'blub'
220
- }
221
- session.left.insert_record 'rr_pending_changes', {
222
- 'change_table' => 'extender_no_record',
223
- 'change_key' => 'id|1',
224
- 'change_type' => 'I',
225
- 'change_time' => Time.now
226
- }
227
- session.left.insert_record 'rr_pending_changes', {
228
- 'change_table' => 'extender_no_record',
229
- 'change_key' => 'id|2',
230
- 'change_type' => 'I',
231
- 'change_time' => Time.now
232
- }
233
-
234
- run = ReplicationRun.new session, TaskSweeper.new(1)
235
- run.run
236
-
237
- session.right.select_records(:table => "extender_no_record").should == [{
238
- 'id' => 2,
239
- 'name' => 'blub'
240
- }]
241
- ensure
242
- Committers::NeverCommitter.rollback_current_session
243
- if session
244
- session.left.execute "delete from extender_no_record"
245
- session.right.execute "delete from extender_no_record"
246
- session.left.execute "delete from rr_pending_changes"
247
- end
248
- end
249
- end
250
-
251
- it "run should not create the replicator if there are no pending changes" do
252
- session = Session.new
253
- run = ReplicationRun.new session, TaskSweeper.new(1)
254
- run.should_not_receive(:replicator)
255
- run.run
256
- end
257
-
258
- it "run should only replicate real differences" do
259
- session = Session.new
260
- session.left.begin_db_transaction
261
- session.right.begin_db_transaction
262
- begin
263
-
264
- session.left.insert_record 'rr_pending_changes', {
265
- 'change_table' => 'extender_no_record',
266
- 'change_key' => 'id|1',
267
- 'change_type' => 'D',
268
- 'change_time' => Time.now
269
- }
270
- session.right.insert_record 'rr_pending_changes', {
271
- 'change_table' => 'extender_no_record',
272
- 'change_key' => 'id|1',
273
- 'change_type' => 'D',
274
- 'change_time' => Time.now
275
- }
276
-
277
- run = ReplicationRun.new session, TaskSweeper.new(1)
278
- run.replicator.should_not_receive(:replicate)
279
- run.run
280
-
281
- ensure
282
- session.left.rollback_db_transaction
283
- session.right.rollback_db_transaction
284
- end
285
- end
286
-
287
- it "run should log raised exceptions" do
288
- session = Session.new
289
- session.left.begin_db_transaction
290
- session.right.begin_db_transaction
291
- begin
292
- session.left.execute "delete from rr_pending_changes"
293
- session.left.execute "delete from rr_logged_events"
294
- session.left.insert_record 'rr_pending_changes', {
295
- 'change_table' => 'extender_no_record',
296
- 'change_key' => 'id|1',
297
- 'change_type' => 'D',
298
- 'change_time' => Time.now
299
- }
300
- run = ReplicationRun.new session, TaskSweeper.new(1)
301
- run.replicator.stub!(:replicate_difference).and_return {raise Exception, 'dummy message'}
302
- run.run
303
-
304
- row = session.left.select_one("select * from rr_logged_events")
305
- row['description'].should == 'dummy message'
306
- row['long_description'].should =~ /Exception/
307
- ensure
308
- session.left.rollback_db_transaction
309
- session.right.rollback_db_transaction
310
- end
311
- end
312
-
313
- it "run should re-raise original exception if logging to database fails" do
314
- session = Session.new
315
- session.left.begin_db_transaction
316
- session.right.begin_db_transaction
317
- begin
318
- session.left.execute "delete from rr_pending_changes"
319
- session.left.execute "delete from rr_logged_events"
320
- session.left.insert_record 'rr_pending_changes', {
321
- 'change_table' => 'extender_no_record',
322
- 'change_key' => 'id|1',
323
- 'change_type' => 'D',
324
- 'change_time' => Time.now
325
- }
326
- run = ReplicationRun.new session, TaskSweeper.new(1)
327
- run.replicator.stub!(:replicate_difference).and_return {raise Exception, 'dummy message'}
328
- run.helper.stub!(:log_replication_outcome).and_return {raise Exception, 'blub'}
329
- lambda {run.run}.should raise_error(Exception, 'dummy message')
330
- ensure
331
- session.left.rollback_db_transaction
332
- session.right.rollback_db_transaction
333
- end
334
- end
335
-
336
- it "run should return silently if timed out before work actually started" do
337
- session = Session.new
338
- session.left.begin_db_transaction
339
- session.right.begin_db_transaction
340
- begin
341
- session.left.execute "delete from rr_pending_changes"
342
- session.left.insert_record 'rr_pending_changes', {
343
- 'change_table' => 'extender_no_record',
344
- 'change_key' => 'id|1',
345
- 'change_type' => 'D',
346
- 'change_time' => Time.now
347
- }
348
- sweeper = TaskSweeper.new(1)
349
- sweeper.stub!(:terminated?).and_return(true)
350
- run = ReplicationRun.new session, sweeper
351
- LoggedChangeLoaders.should_not_receive(:new)
352
- run.run
353
- ensure
354
- session.left.rollback_db_transaction
355
- session.right.rollback_db_transaction
356
- end
357
- end
358
-
359
- it "run should rollback if timed out" do
360
- session = Session.new
361
- session.left.begin_db_transaction
362
- session.right.begin_db_transaction
363
- begin
364
- session.left.execute "delete from rr_pending_changes"
365
- session.left.execute "delete from rr_logged_events"
366
- session.left.insert_record 'rr_pending_changes', {
367
- 'change_table' => 'extender_no_record',
368
- 'change_key' => 'id|1',
369
- 'change_type' => 'D',
370
- 'change_time' => Time.now
371
- }
372
- sweeper = TaskSweeper.new(1)
373
- sweeper.should_receive(:terminated?).any_number_of_times.and_return(false, true)
374
- run = ReplicationRun.new session, sweeper
375
- run.helper.should_receive(:finalize).with(false)
376
- run.run
377
- ensure
378
- session.left.rollback_db_transaction if session.left
379
- session.right.rollback_db_transaction if session.right
380
- end
381
- end
382
-
383
- it "run should not catch exceptions raised during replicator initialization" do
384
- config = deep_copy(standard_config)
385
- config.options[:logged_replication_events] = [:invalid_option]
386
- session = Session.new config
387
- session.left.begin_db_transaction
388
- begin
389
-
390
- session.left.insert_record 'rr_pending_changes', {
391
- 'change_table' => 'extender_no_record',
392
- 'change_key' => 'id|1',
393
- 'change_type' => 'D',
394
- 'change_time' => Time.now
395
- }
396
-
397
- run = ReplicationRun.new session, TaskSweeper.new(1)
398
- lambda {run.run}.should raise_error(ArgumentError)
399
- ensure
400
- session.left.rollback_db_transaction
401
- end
402
- end
403
-
404
- it "run should process trigger created change log records" do
405
- begin
406
- config = deep_copy(standard_config)
407
- config.options[:committer] = :never_commit
408
- config.options[:logged_replication_events] = [:all_changes]
409
-
410
- session = Session.new(config)
411
- session.left.execute "delete from rr_logged_events"
412
- initializer = ReplicationInitializer.new(session)
413
- initializer.create_trigger :left, 'extender_no_record'
414
-
415
- session.left.insert_record 'extender_no_record', {
416
- 'id' => '1',
417
- 'name' => 'bla'
418
- }
419
-
420
- run = ReplicationRun.new session, TaskSweeper.new(1)
421
- run.run
422
-
423
- session.right.select_record(:table => "extender_no_record").should == {
424
- 'id' => 1,
425
- 'name' => 'bla'
426
- }
427
-
428
- # also verify that event was logged
429
- row = session.left.select_one("select * from rr_logged_events")
430
- row['diff_type'].should == 'left'
431
- row['change_key'].should == '1'
432
- row['description'].should == 'replicated'
433
- ensure
434
- Committers::NeverCommitter.rollback_current_session
435
- if session
436
- session.left.execute "delete from extender_no_record"
437
- session.right.execute "delete from extender_no_record"
438
- session.left.execute "delete from rr_pending_changes"
439
- end
440
- initializer.drop_trigger :left, 'extender_no_record' if initializer
441
- end
442
- end
443
- end
@@ -1,254 +0,0 @@
1
- require File.dirname(__FILE__) + '/spec_helper.rb'
2
-
3
- include RR
4
-
5
- describe ReplicationRunner do
6
- before(:each) do
7
- Initializer.configuration = standard_config
8
- end
9
-
10
- it "should register itself with CommandRunner" do
11
- CommandRunner.commands['replicate'][:command].should == ReplicationRunner
12
- CommandRunner.commands['replicate'][:description].should be_an_instance_of(String)
13
- end
14
-
15
- it "process_options should make options as nil and teturn status as 1 if command line parameters are unknown" do
16
- # also verify that an error message is printed
17
- $stderr.should_receive(:puts).any_number_of_times
18
- runner = ReplicationRunner.new
19
- status = runner.process_options ["--nonsense"]
20
- runner.options.should == nil
21
- status.should == 1
22
- end
23
-
24
- it "process_options should make options as nil and return status as 1 if config option is not given" do
25
- # also verify that an error message is printed
26
- $stderr.should_receive(:puts).any_number_of_times
27
- runner = ReplicationRunner.new
28
- status = runner.process_options []
29
- runner.options.should == nil
30
- status.should == 1
31
- end
32
-
33
- it "process_options should make options as nil and return status as 0 if command line includes '--help'" do
34
- # also verify that the help message is printed
35
- $stderr.should_receive(:puts)
36
- runner = ReplicationRunner.new
37
- status = runner.process_options ["--help"]
38
- runner.options.should == nil
39
- status.should == 0
40
- end
41
-
42
- it "process_options should set the correct options" do
43
- runner = ReplicationRunner.new
44
- runner.process_options ["-c", "config_path"]
45
- runner.options[:config_file].should == 'config_path'
46
- end
47
-
48
- it "run should not start a replication if the command line is invalid" do
49
- $stderr.should_receive(:puts).any_number_of_times
50
- ReplicationRunner.any_instance_should_not_receive(:execute) {
51
- ReplicationRunner.run(["--nonsense"])
52
- }
53
- end
54
-
55
- it "run should start a replication if the command line is correct" do
56
- ReplicationRunner.any_instance_should_receive(:execute) {
57
- ReplicationRunner.run(["--config=path"])
58
- }
59
- end
60
-
61
- it "session should create and return the session" do
62
- runner = ReplicationRunner.new
63
- runner.options = {:config_file => "config/test_config.rb"}
64
- runner.session.should be_an_instance_of(Session)
65
- runner.session.should == runner.session # should only be created one time
66
- end
67
-
68
- it "pause_replication should not pause if next replication is already overdue" do
69
- runner = ReplicationRunner.new
70
- runner.stub!(:session).and_return(Session.new(standard_config))
71
- waiter_thread = mock('waiter_thread')
72
- waiter_thread.should_not_receive(:join)
73
- runner.instance_variable_set(:@waiter_thread, waiter_thread)
74
-
75
- runner.pause_replication # verify no wait during first run
76
- runner.instance_variable_set(:@last_run, 1.hour.ago)
77
- runner.pause_replication # verify no wait if overdue
78
- end
79
-
80
- it "pause_replication should pause for correct time frame" do
81
- runner = ReplicationRunner.new
82
- runner.stub!(:session).and_return(Session.new(deep_copy(standard_config)))
83
- runner.session.configuration.stub!(:options).and_return(:replication_interval => 2)
84
- waiter_thread = mock('waiter_thread')
85
- runner.instance_variable_set(:@waiter_thread, waiter_thread)
86
-
87
- now = Time.now
88
- Time.stub!(:now).and_return(now)
89
- runner.instance_variable_set(:@last_run, now - 1.seconds)
90
- waiter_thread.should_receive(:join).and_return {|time| time.to_f.should be_close(1.0, 0.01); 0}
91
-
92
- runner.pause_replication
93
- end
94
-
95
- it "init_waiter should setup correct signal processing" do
96
- org_stdout = $stdout
97
- $stdout = StringIO.new
98
- begin
99
- runner = ReplicationRunner.new
100
- runner.stub!(:session).and_return(Session.new(standard_config))
101
-
102
- # simulate sending the TERM signal
103
- Signal.should_receive(:trap).with('TERM').and_yield
104
-
105
- # also verify that the INT signal is trapped
106
- Signal.should_receive(:trap).with('INT')
107
-
108
- runner.init_waiter
109
-
110
- # verify the that any pause would have been prematurely finished and
111
- # termination signal been set
112
- runner.termination_requested.should be_true
113
- runner.instance_variable_get(:@waiter_thread).should_not be_alive
114
- $stdout.string.should =~ /TERM.*shutdown/
115
- ensure
116
- $stdout = org_stdout
117
- end
118
- end
119
-
120
- it "prepare_replication should call ReplicationInitializer#prepare_replication" do
121
- runner = ReplicationRunner.new
122
- runner.stub!(:session).and_return(:dummy_session)
123
- initializer = mock('replication_initializer')
124
- initializer.should_receive(:prepare_replication)
125
- ReplicationInitializer.should_receive(:new).with(:dummy_session).and_return(initializer)
126
- runner.prepare_replication
127
- end
128
-
129
- # Checks a specified number of times with specified waiting period between
130
- # attempts if a given SQL query returns records.
131
- # Returns +true+ if a record was found
132
- # * +session+: an active Session object
133
- # * +database+: either :+left+ or :+right+
134
- # * +query+: sql query to execute
135
- # * +max_attempts+: number of attempts to find the record
136
- # * +interval+: waiting time in seconds between attempts
137
- def check_for_record(session, database, query, max_attempts, interval)
138
- found = false
139
-
140
- max_attempts.times do
141
- found = !!session.send(database).select_one(query)
142
- break if found
143
- sleep interval
144
- end
145
-
146
- found
147
- end
148
-
149
- it "execute should catch and print exceptions" do
150
- org_stderr = $stderr
151
- $stderr = StringIO.new
152
- begin
153
- session = Session.new
154
- runner = ReplicationRunner.new
155
- runner.stub!(:session).and_return(session)
156
- runner.stub!(:init_waiter)
157
- runner.stub!(:prepare_replication)
158
- runner.stub!(:pause_replication)
159
- runner.should_receive(:termination_requested).twice.and_return(false, true)
160
-
161
- session.should_receive(:refresh).and_return {raise "refresh failed"}
162
-
163
- runner.execute
164
-
165
- $stderr.string.should =~ /Exception caught.*refresh failed/
166
- $stderr.string.should =~ /replication_runner.rb:[0-9]+:in/
167
- ensure
168
- $stderr = org_stderr
169
- end
170
- end
171
-
172
- it "execute_once should not clean up if successful" do
173
- runner = ReplicationRunner.new
174
- session = Session.new
175
- runner.instance_variable_set(:@session, session)
176
-
177
- runner.execute_once
178
- runner.instance_variable_get(:@session).should == session
179
- end
180
-
181
- it "execute_once should clean up after failed replication runs" do
182
- runner = ReplicationRunner.new
183
- session = Session.new
184
- runner.instance_variable_set(:@session, session)
185
-
186
- session.should_receive(:refresh).and_raise('bla')
187
- lambda {runner.execute_once}.should raise_error('bla')
188
- runner.instance_variable_get(:@session).should be_nil
189
- end
190
-
191
- it "execute_once should raise exception if replication run times out" do
192
- session = Session.new
193
- runner = ReplicationRunner.new
194
- runner.stub!(:session).and_return(session)
195
- terminated = mock("terminated")
196
- terminated.stub!(:terminated?).and_return(true)
197
- TaskSweeper.stub!(:timeout).and_return(terminated)
198
-
199
- lambda {runner.execute_once}.should raise_error(/timed out/)
200
- end
201
-
202
- it "execute should start the replication" do
203
- config = deep_copy(standard_config)
204
- config.options[:committer] = :buffered_commit
205
- config.options[:replication_interval] = 0.01
206
-
207
- # reset table selection
208
- config.included_table_specs.replace ['scanner_left_records_only']
209
- config.tables_with_options.clear
210
-
211
- session = Session.new config
212
- org_stdout = $stdout
213
- begin
214
- $stdout = StringIO.new
215
- runner = ReplicationRunner.new
216
- runner.process_options ["-c", "./config/test_config.rb"]
217
- runner.stub!(:session).and_return(session)
218
-
219
- t = Thread.new {runner.execute}
220
-
221
- # verify that the initial sync is done
222
- found = check_for_record(
223
- session, :right,
224
- "select * from scanner_left_records_only where id = 1",
225
- 100, 0.01
226
- )
227
- t.should be_alive # verify that the replication thread didn't die
228
- found.should be_true
229
-
230
- session.left.execute "insert into scanner_left_records_only(name) values('bla')"
231
-
232
- # verify that the replication works
233
- check_for_record(
234
- session, :right,
235
- "select * from scanner_left_records_only where name = 'bla'",
236
- 100, 0.01
237
- ).should be_true
238
-
239
- runner.instance_variable_set(:@termination_requested, true)
240
- t.join
241
- ensure
242
- $stdout = org_stdout
243
- initializer = ReplicationInitializer.new session
244
- [:left, :right].each do |database|
245
- initializer.clear_sequence_setup database, 'scanner_left_records_only'
246
- if initializer.trigger_exists?(database, 'scanner_left_records_only')
247
- initializer.drop_trigger database, 'scanner_left_records_only'
248
- end
249
- session.send(database).execute "delete from scanner_left_records_only where name = 'bla'"
250
- end
251
- session.right.execute "delete from scanner_left_records_only"
252
- end
253
- end
254
- end