rubyrep 1.2.0 → 2.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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +84 -0
- data/History.txt +6 -0
- data/README.txt +1 -1
- data/Rakefile +6 -27
- data/bin/rubyrep +1 -1
- data/config/mysql_config.rb +2 -2
- data/config/postgres_config.rb +5 -3
- data/lib/rubyrep/command_runner.rb +1 -1
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +30 -44
- data/lib/rubyrep/connection_extenders/mysql_extender.rb +23 -1
- data/lib/rubyrep/connection_extenders/postgresql_extender.rb +31 -168
- data/lib/rubyrep/generate_runner.rb +1 -1
- data/lib/rubyrep/logged_change.rb +1 -1
- data/lib/rubyrep/proxy_connection.rb +22 -12
- data/lib/rubyrep/replication_difference.rb +1 -1
- data/lib/rubyrep/replication_extenders/mysql_replication.rb +1 -1
- data/lib/rubyrep/replication_helper.rb +1 -1
- data/lib/rubyrep/replication_runner.rb +10 -0
- data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +1 -1
- data/lib/rubyrep/table_spec_resolver.rb +1 -1
- data/lib/rubyrep/type_casting_cursor.rb +8 -4
- data/lib/rubyrep/version.rb +1 -7
- data/lib/rubyrep.rb +4 -3
- data/rubyrep +4 -0
- data/rubyrep.bat +5 -0
- data/rubyrep.gemspec +29 -0
- data/sims/performance/big_rep_spec.rb +34 -17
- data/sims/performance/performance.rake +11 -31
- data/tasks/database.rake +14 -14
- data/tasks/java.rake +18 -5
- data/tasks/rspec.rake +14 -34
- data/tasks/stats.rake +1 -16
- metadata +99 -162
- data/.gemtest +0 -0
- data/config/requirements.rb +0 -32
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +0 -65
- data/spec/base_runner_spec.rb +0 -218
- data/spec/buffered_committer_spec.rb +0 -274
- data/spec/command_runner_spec.rb +0 -145
- data/spec/committers_spec.rb +0 -178
- data/spec/configuration_spec.rb +0 -203
- data/spec/connection_extender_interface_spec.rb +0 -141
- data/spec/connection_extenders_registration_spec.rb +0 -164
- data/spec/database_proxy_spec.rb +0 -48
- data/spec/database_rake_spec.rb +0 -40
- data/spec/db_specific_connection_extenders_spec.rb +0 -34
- data/spec/db_specific_replication_extenders_spec.rb +0 -38
- data/spec/direct_table_scan_spec.rb +0 -61
- data/spec/dolphins.jpg +0 -0
- data/spec/generate_runner_spec.rb +0 -84
- data/spec/initializer_spec.rb +0 -46
- data/spec/log_helper_spec.rb +0 -39
- data/spec/logged_change_loader_spec.rb +0 -68
- data/spec/logged_change_spec.rb +0 -470
- data/spec/noisy_connection_spec.rb +0 -78
- data/spec/postgresql_replication_spec.rb +0 -48
- data/spec/postgresql_schema_support_spec.rb +0 -212
- data/spec/postgresql_support_spec.rb +0 -63
- data/spec/progress_bar_spec.rb +0 -77
- data/spec/proxied_table_scan_spec.rb +0 -151
- data/spec/proxy_block_cursor_spec.rb +0 -197
- data/spec/proxy_connection_spec.rb +0 -423
- data/spec/proxy_cursor_spec.rb +0 -56
- data/spec/proxy_row_cursor_spec.rb +0 -66
- data/spec/proxy_runner_spec.rb +0 -70
- data/spec/replication_difference_spec.rb +0 -161
- data/spec/replication_extender_interface_spec.rb +0 -367
- data/spec/replication_extenders_spec.rb +0 -32
- data/spec/replication_helper_spec.rb +0 -178
- data/spec/replication_initializer_spec.rb +0 -509
- data/spec/replication_run_spec.rb +0 -443
- data/spec/replication_runner_spec.rb +0 -254
- data/spec/replicators_spec.rb +0 -36
- data/spec/rubyrep_spec.rb +0 -8
- data/spec/scan_detail_reporter_spec.rb +0 -119
- data/spec/scan_progress_printers_spec.rb +0 -68
- data/spec/scan_report_printers_spec.rb +0 -67
- data/spec/scan_runner_spec.rb +0 -50
- data/spec/scan_summary_reporter_spec.rb +0 -61
- data/spec/session_spec.rb +0 -253
- data/spec/spec.opts +0 -1
- data/spec/spec_helper.rb +0 -305
- data/spec/strange_name_support_spec.rb +0 -135
- data/spec/sync_helper_spec.rb +0 -169
- data/spec/sync_runner_spec.rb +0 -78
- data/spec/syncers_spec.rb +0 -171
- data/spec/table_scan_helper_spec.rb +0 -36
- data/spec/table_scan_spec.rb +0 -49
- data/spec/table_sorter_spec.rb +0 -30
- data/spec/table_spec_resolver_spec.rb +0 -111
- data/spec/table_sync_spec.rb +0 -140
- data/spec/task_sweeper_spec.rb +0 -47
- data/spec/trigger_mode_switcher_spec.rb +0 -83
- data/spec/two_way_replicator_spec.rb +0 -721
- data/spec/two_way_syncer_spec.rb +0 -256
- data/spec/type_casting_cursor_spec.rb +0 -50
- data/spec/uninstall_runner_spec.rb +0 -93
- data/tasks/rubyrep.tailor +0 -18
- data/tasks/website.rake +0 -19
|
@@ -1,721 +0,0 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
-
|
|
3
|
-
include RR
|
|
4
|
-
|
|
5
|
-
describe Replicators::TwoWayReplicator do
|
|
6
|
-
before(:each) do
|
|
7
|
-
Initializer.configuration = deep_copy(standard_config)
|
|
8
|
-
Initializer.configuration.options = {:replicator => :two_way}
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it "should register itself" do
|
|
12
|
-
Replicators::replicators[:two_way].should == Replicators::TwoWayReplicator
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "initialize should store the replication helper" do
|
|
16
|
-
rep_run = ReplicationRun.new(Session.new, TaskSweeper.new(1))
|
|
17
|
-
helper = ReplicationHelper.new(rep_run)
|
|
18
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
19
|
-
replicator.rep_helper.should == helper
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it "verify_option should raise descriptive errors" do
|
|
23
|
-
rep_run = ReplicationRun.new(Session.new, TaskSweeper.new(1))
|
|
24
|
-
helper = ReplicationHelper.new(rep_run)
|
|
25
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
26
|
-
lambda {replicator.verify_option(nil, [:valid_value], :my_key, :my_value)}.
|
|
27
|
-
should raise_error(ArgumentError, ':my_value not a valid :my_key option')
|
|
28
|
-
lambda {replicator.verify_option(/my_spec/, [:valid_value], :my_key, :my_value)}.
|
|
29
|
-
should raise_error(ArgumentError, '/my_spec/: :my_value not a valid :my_key option')
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it "initialize should throw an error if options are invalid" do
|
|
33
|
-
rep_run = ReplicationRun.new(Session.new, TaskSweeper.new(1))
|
|
34
|
-
helper = ReplicationHelper.new(rep_run)
|
|
35
|
-
base_options = {
|
|
36
|
-
:replicator => :two_way,
|
|
37
|
-
:left_change_handling => :ignore,
|
|
38
|
-
:right_change_handling => :ignore,
|
|
39
|
-
:replication_conflict_handling => :ignore,
|
|
40
|
-
:logged_replication_events => [:ignored_conflicts]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
# Verify that correct options don't raise errors.
|
|
44
|
-
helper.stub!(:options).and_return(base_options)
|
|
45
|
-
lambda {Replicators::TwoWayReplicator.new(helper)}.should_not raise_error
|
|
46
|
-
|
|
47
|
-
# Also lambda options should not raise errors.
|
|
48
|
-
l = lambda {}
|
|
49
|
-
helper.stub!(:options).and_return(base_options.merge(
|
|
50
|
-
{
|
|
51
|
-
:left_change_handling => l,
|
|
52
|
-
:right_change_handling => l,
|
|
53
|
-
:repliction_conflict_handling => l
|
|
54
|
-
})
|
|
55
|
-
)
|
|
56
|
-
lambda {Replicators::TwoWayReplicator.new(helper)}.should_not raise_error
|
|
57
|
-
|
|
58
|
-
# Invalid options should raise errors
|
|
59
|
-
invalid_options = [
|
|
60
|
-
{:left_change_handling => :invalid_left_option},
|
|
61
|
-
{:right_change_handling => :invalid_right_option},
|
|
62
|
-
{:replication_conflict_handling => :invalid_conflict_option},
|
|
63
|
-
{:logged_replication_events => :invalid_logging_option},
|
|
64
|
-
]
|
|
65
|
-
invalid_options.each do |options|
|
|
66
|
-
helper.session.configuration.stub!(:options).and_return(base_options.merge(options))
|
|
67
|
-
lambda {Replicators::TwoWayReplicator.new(helper)}.should raise_error(ArgumentError)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "clear_conflicts should update the correct database with the correct action" do
|
|
72
|
-
Initializer.configuration.include_tables 'left_table, right_table'
|
|
73
|
-
session = Session.new
|
|
74
|
-
session.left.begin_db_transaction
|
|
75
|
-
session.right.begin_db_transaction
|
|
76
|
-
begin
|
|
77
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
78
|
-
helper = ReplicationHelper.new(rep_run)
|
|
79
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
80
|
-
|
|
81
|
-
loaders = LoggedChangeLoaders.new(session)
|
|
82
|
-
|
|
83
|
-
left_change = LoggedChange.new loaders[:left]
|
|
84
|
-
left_change.table = 'left_table'
|
|
85
|
-
left_change.key = {'id' => '1'}
|
|
86
|
-
right_change = LoggedChange.new loaders[:right]
|
|
87
|
-
right_change.table = 'right_table'
|
|
88
|
-
right_change.key = {'id' => '1'}
|
|
89
|
-
|
|
90
|
-
diff = ReplicationDifference.new(loaders)
|
|
91
|
-
diff.changes[:left] = left_change
|
|
92
|
-
diff.changes[:right] = right_change
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# verify that an insert is dealt correctly with
|
|
96
|
-
left_change.type = :insert
|
|
97
|
-
right_change.type = :insert
|
|
98
|
-
|
|
99
|
-
helper.should_receive(:load_record).ordered.
|
|
100
|
-
with(:left, 'left_table', {'id' => '1'}).
|
|
101
|
-
and_return(:dummy_values)
|
|
102
|
-
helper.should_receive(:update_record).ordered.
|
|
103
|
-
with(:right, 'right_table', :dummy_values, {'id' => '1'})
|
|
104
|
-
replicator.clear_conflict :left, diff, 1
|
|
105
|
-
|
|
106
|
-
# verify that an update is dealt correctly with
|
|
107
|
-
left_change.type = :delete
|
|
108
|
-
right_change.type = :update
|
|
109
|
-
right_change.new_key = {'id' => '2'}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
helper.should_receive(:load_record).ordered.
|
|
113
|
-
with(:right, 'right_table', {'id' => '2'}).
|
|
114
|
-
and_return(:dummy_values)
|
|
115
|
-
helper.should_receive(:insert_record).ordered.
|
|
116
|
-
with(:left, 'left_table', :dummy_values)
|
|
117
|
-
replicator.clear_conflict :right, diff, 1
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# verify that a delete is dealt correctly with
|
|
121
|
-
left_change.type = :delete
|
|
122
|
-
right_change.type = :update
|
|
123
|
-
|
|
124
|
-
helper.should_receive(:delete_record).ordered.
|
|
125
|
-
with(:right, 'right_table', {'id' => '2'})
|
|
126
|
-
replicator.clear_conflict :left, diff, 1
|
|
127
|
-
ensure
|
|
128
|
-
session.left.rollback_db_transaction
|
|
129
|
-
session.right.rollback_db_transaction
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
it "log_replication_outcome should log conflicts correctly" do
|
|
134
|
-
session = Session.new
|
|
135
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
136
|
-
|
|
137
|
-
loaders = LoggedChangeLoaders.new(session)
|
|
138
|
-
|
|
139
|
-
diff = ReplicationDifference.new loaders
|
|
140
|
-
diff.type = :conflict
|
|
141
|
-
diff.changes[:left] = LoggedChange.new loaders[:left]
|
|
142
|
-
diff.changes[:left].table = 'scanner_records'
|
|
143
|
-
|
|
144
|
-
# should only log events if so configured
|
|
145
|
-
helper = ReplicationHelper.new(rep_run)
|
|
146
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
147
|
-
helper.should_not_receive(:log_replication_outcome)
|
|
148
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => []})
|
|
149
|
-
replicator.log_replication_outcome :ignore, diff
|
|
150
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => [:ignored_conflicts]})
|
|
151
|
-
replicator.log_replication_outcome :left, diff
|
|
152
|
-
|
|
153
|
-
# should log ignored conflicts correctly
|
|
154
|
-
helper = ReplicationHelper.new(rep_run)
|
|
155
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
156
|
-
helper.should_receive(:log_replication_outcome).with(diff, 'ignored')
|
|
157
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => [:ignored_conflicts]})
|
|
158
|
-
replicator.log_replication_outcome :ignore, diff
|
|
159
|
-
|
|
160
|
-
# should log conflicts correctly
|
|
161
|
-
helper = ReplicationHelper.new(rep_run)
|
|
162
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
163
|
-
helper.should_receive(:log_replication_outcome).with(diff, 'left_won')
|
|
164
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => [:all_conflicts]})
|
|
165
|
-
replicator.log_replication_outcome :left, diff
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
it "log_replication_outcome should log changes correctly" do
|
|
169
|
-
session = Session.new
|
|
170
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
171
|
-
|
|
172
|
-
loaders = LoggedChangeLoaders.new(session)
|
|
173
|
-
|
|
174
|
-
diff = ReplicationDifference.new loaders
|
|
175
|
-
diff.type = :left
|
|
176
|
-
diff.changes[:left] = LoggedChange.new loaders[:left]
|
|
177
|
-
diff.changes[:left].table = 'scanner_records'
|
|
178
|
-
|
|
179
|
-
# should only log events if so configured
|
|
180
|
-
helper = ReplicationHelper.new(rep_run)
|
|
181
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
182
|
-
helper.should_not_receive(:log_replication_outcome)
|
|
183
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => []})
|
|
184
|
-
replicator.log_replication_outcome :ignore, diff
|
|
185
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => [:ignored_changes]})
|
|
186
|
-
replicator.log_replication_outcome :left, diff
|
|
187
|
-
|
|
188
|
-
# should log changes correctly
|
|
189
|
-
helper = ReplicationHelper.new(rep_run)
|
|
190
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
191
|
-
helper.should_receive(:log_replication_outcome).with(diff, 'replicated')
|
|
192
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => [:all_changes]})
|
|
193
|
-
replicator.log_replication_outcome :right, diff
|
|
194
|
-
|
|
195
|
-
# should log changes correctly
|
|
196
|
-
helper = ReplicationHelper.new(rep_run)
|
|
197
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
198
|
-
helper.should_receive(:log_replication_outcome).with(diff, 'ignored')
|
|
199
|
-
helper.stub!(:options_for_table).and_return({:logged_replication_events => [:ignored_changes]})
|
|
200
|
-
replicator.log_replication_outcome :ignore, diff
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
it "replicate_difference should not do anything if ignore option is given" do
|
|
204
|
-
session = Session.new
|
|
205
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
206
|
-
helper = ReplicationHelper.new(rep_run)
|
|
207
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
208
|
-
helper.stub!(:options_for_table).and_return(
|
|
209
|
-
{
|
|
210
|
-
:left_change_handling => :ignore,
|
|
211
|
-
:right_change_handling => :ignore,
|
|
212
|
-
:replication_conflict_handling => :ignore,
|
|
213
|
-
:logged_replication_events => [:ignored_changes, :ignored_conflicts]
|
|
214
|
-
}
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
loaders = LoggedChangeLoaders.new(session)
|
|
218
|
-
|
|
219
|
-
diff = ReplicationDifference.new(loaders)
|
|
220
|
-
diff.changes[:left] = LoggedChange.new loaders[:left]
|
|
221
|
-
diff.changes[:left].table = 'scanner_records'
|
|
222
|
-
|
|
223
|
-
# but logging should still happen
|
|
224
|
-
replicator.should_receive(:log_replication_outcome).
|
|
225
|
-
with(:ignore, diff).
|
|
226
|
-
exactly(3).times
|
|
227
|
-
|
|
228
|
-
helper.should_not_receive :insert_record
|
|
229
|
-
helper.should_not_receive :update_record
|
|
230
|
-
helper.should_not_receive :delete_record
|
|
231
|
-
|
|
232
|
-
diff.type = :conflict
|
|
233
|
-
replicator.replicate_difference diff
|
|
234
|
-
diff.type = :left
|
|
235
|
-
replicator.replicate_difference diff
|
|
236
|
-
diff.type = :right
|
|
237
|
-
replicator.replicate_difference diff
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
it "replicate_difference should call the provided Proc objects" do
|
|
241
|
-
session = Session.new
|
|
242
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
243
|
-
helper = ReplicationHelper.new(rep_run)
|
|
244
|
-
|
|
245
|
-
lambda_parameters = []
|
|
246
|
-
l = lambda do |rep_helper, diff|
|
|
247
|
-
lambda_parameters << [rep_helper, diff]
|
|
248
|
-
end
|
|
249
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
250
|
-
helper.stub!(:options_for_table).and_return(
|
|
251
|
-
{
|
|
252
|
-
:left_change_handling => l,
|
|
253
|
-
:right_change_handling => l,
|
|
254
|
-
:replication_conflict_handling => l
|
|
255
|
-
}
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
loaders = LoggedChangeLoaders.new(session)
|
|
259
|
-
|
|
260
|
-
change = LoggedChange.new loaders[:left]
|
|
261
|
-
change.table = 'scanner_records'
|
|
262
|
-
|
|
263
|
-
d1 = ReplicationDifference.new(loaders)
|
|
264
|
-
d1.type = :conflict
|
|
265
|
-
d1.changes[:left] = change
|
|
266
|
-
replicator.replicate_difference d1
|
|
267
|
-
|
|
268
|
-
d2 = ReplicationDifference.new(loaders)
|
|
269
|
-
d2.type = :left
|
|
270
|
-
d2.changes[:left] = change
|
|
271
|
-
replicator.replicate_difference d2
|
|
272
|
-
|
|
273
|
-
d3 = ReplicationDifference.new(loaders)
|
|
274
|
-
d3.type = :right
|
|
275
|
-
d3.changes[:left] = change
|
|
276
|
-
replicator.replicate_difference d3
|
|
277
|
-
|
|
278
|
-
lambda_parameters.should == [
|
|
279
|
-
[helper, d1],
|
|
280
|
-
[helper, d2],
|
|
281
|
-
[helper, d3],
|
|
282
|
-
]
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
it "replicate_difference should clear conflicts as per provided options" do
|
|
286
|
-
session = Session.new
|
|
287
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
288
|
-
helper = ReplicationHelper.new(rep_run)
|
|
289
|
-
|
|
290
|
-
left_change = LoggedChange.new LoggedChangeLoader.new(session, :left)
|
|
291
|
-
left_change.table = 'scanner_records'
|
|
292
|
-
right_change = LoggedChange.new LoggedChangeLoader.new(session, :right)
|
|
293
|
-
right_change.table = 'scanner_records'
|
|
294
|
-
diff = ReplicationDifference.new(session)
|
|
295
|
-
diff.type = :conflict
|
|
296
|
-
diff.changes[:left] = left_change
|
|
297
|
-
diff.changes[:right] = right_change
|
|
298
|
-
|
|
299
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
300
|
-
helper.stub!(:options_for_table).and_return({:replication_conflict_handling => :left_wins})
|
|
301
|
-
replicator.should_receive(:clear_conflict).with(:left, diff, 1)
|
|
302
|
-
replicator.replicate_difference diff, 1
|
|
303
|
-
|
|
304
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
305
|
-
helper.stub!(:options_for_table).and_return({:replication_conflict_handling => :right_wins})
|
|
306
|
-
replicator.should_receive(:clear_conflict).with(:right, diff, 1)
|
|
307
|
-
replicator.replicate_difference diff, 1
|
|
308
|
-
|
|
309
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
310
|
-
helper.stub!(:options_for_table).and_return({:replication_conflict_handling => :later_wins})
|
|
311
|
-
replicator.should_receive(:clear_conflict).with(:left, diff, 1).twice
|
|
312
|
-
left_change.last_changed_at = 5.seconds.from_now
|
|
313
|
-
right_change.last_changed_at = Time.now
|
|
314
|
-
replicator.replicate_difference diff, 1
|
|
315
|
-
left_change.last_changed_at = right_change.last_changed_at = Time.now
|
|
316
|
-
replicator.replicate_difference diff, 1
|
|
317
|
-
replicator.should_receive(:clear_conflict).with(:right, diff, 1)
|
|
318
|
-
right_change.last_changed_at = 5.seconds.from_now
|
|
319
|
-
replicator.replicate_difference diff, 1
|
|
320
|
-
|
|
321
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
322
|
-
helper.stub!(:options_for_table).and_return({:replication_conflict_handling => :earlier_wins})
|
|
323
|
-
replicator.should_receive(:clear_conflict).with(:left, diff, 1).twice
|
|
324
|
-
left_change.last_changed_at = 5.seconds.ago
|
|
325
|
-
right_change.last_changed_at = Time.now
|
|
326
|
-
replicator.replicate_difference diff, 1
|
|
327
|
-
left_change.last_changed_at = right_change.last_changed_at = Time.now
|
|
328
|
-
replicator.replicate_difference diff, 1
|
|
329
|
-
replicator.should_receive(:clear_conflict).with(:right, diff, 1)
|
|
330
|
-
right_change.last_changed_at = 5.seconds.ago
|
|
331
|
-
replicator.replicate_difference diff, 1
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
it "replicate_difference should replicate :left / :right changes correctly" do
|
|
335
|
-
Initializer.configuration.include_tables 'left_table, right_table'
|
|
336
|
-
session = Session.new
|
|
337
|
-
session.left.begin_db_transaction
|
|
338
|
-
session.right.begin_db_transaction
|
|
339
|
-
begin
|
|
340
|
-
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
|
341
|
-
|
|
342
|
-
left_change = LoggedChange.new LoggedChangeLoader.new(session, :left)
|
|
343
|
-
left_change.table = 'left_table'
|
|
344
|
-
left_change.key = {'id' => '1'}
|
|
345
|
-
right_change = LoggedChange.new LoggedChangeLoader.new(session, :right)
|
|
346
|
-
right_change.table = 'right_table'
|
|
347
|
-
right_change.key = {'id' => '1'}
|
|
348
|
-
|
|
349
|
-
diff = ReplicationDifference.new(session)
|
|
350
|
-
|
|
351
|
-
# verify insert behaviour
|
|
352
|
-
left_change.type = :insert
|
|
353
|
-
diff.type = :left
|
|
354
|
-
diff.changes[:left] = left_change
|
|
355
|
-
diff.changes[:right] = nil
|
|
356
|
-
|
|
357
|
-
helper = ReplicationHelper.new(rep_run)
|
|
358
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
359
|
-
replicator.should_receive(:log_replication_outcome).with(:left, diff)
|
|
360
|
-
helper.should_receive(:load_record).with(:left, 'left_table', {'id' => '1'}).
|
|
361
|
-
and_return(:dummy_values)
|
|
362
|
-
helper.should_receive(:insert_record).with(:right, 'right_table', :dummy_values)
|
|
363
|
-
replicator.replicate_difference diff
|
|
364
|
-
|
|
365
|
-
# verify update behaviour
|
|
366
|
-
right_change.type = :update
|
|
367
|
-
right_change.new_key = {'id' => '2'}
|
|
368
|
-
diff.type = :right
|
|
369
|
-
diff.changes[:right] = right_change
|
|
370
|
-
|
|
371
|
-
helper = ReplicationHelper.new(rep_run)
|
|
372
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
373
|
-
replicator.should_receive(:log_replication_outcome).with(:right, diff)
|
|
374
|
-
helper.should_receive(:load_record).with(:right, 'right_table', {'id' => '2'}).
|
|
375
|
-
and_return(:dummy_values)
|
|
376
|
-
helper.should_receive(:update_record).with(:left, 'left_table', :dummy_values, {'id' => '1'})
|
|
377
|
-
replicator.replicate_difference diff
|
|
378
|
-
|
|
379
|
-
# verify delete behaviour
|
|
380
|
-
right_change.type = :delete
|
|
381
|
-
|
|
382
|
-
helper = ReplicationHelper.new(rep_run)
|
|
383
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
384
|
-
replicator.should_receive(:log_replication_outcome).with(:right, diff)
|
|
385
|
-
helper.should_receive(:delete_record).with(:left, 'left_table', {'id' => '1'})
|
|
386
|
-
replicator.replicate_difference diff
|
|
387
|
-
ensure
|
|
388
|
-
session.left.rollback_db_transaction
|
|
389
|
-
session.right.rollback_db_transaction
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
it "replicate_difference should handle inserts failing due duplicate records getting created after the original diff was loaded" do
|
|
394
|
-
begin
|
|
395
|
-
config = deep_copy(standard_config)
|
|
396
|
-
config.options[:committer] = :never_commit
|
|
397
|
-
config.options[:replication_conflict_handling] = :right_wins
|
|
398
|
-
|
|
399
|
-
session = Session.new(config)
|
|
400
|
-
|
|
401
|
-
session.left.insert_record 'extender_no_record', {
|
|
402
|
-
'id' => '1',
|
|
403
|
-
'name' => 'bla'
|
|
404
|
-
}
|
|
405
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
406
|
-
'change_table' => 'extender_no_record',
|
|
407
|
-
'change_key' => 'id|1',
|
|
408
|
-
'change_type' => 'I',
|
|
409
|
-
'change_time' => Time.now
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
414
|
-
helper = ReplicationHelper.new(rep_run)
|
|
415
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
416
|
-
|
|
417
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
418
|
-
diff.load
|
|
419
|
-
|
|
420
|
-
session.right.insert_record 'extender_no_record', {
|
|
421
|
-
'id' => '1',
|
|
422
|
-
'name' => 'blub'
|
|
423
|
-
}
|
|
424
|
-
session.right.insert_record 'rr_pending_changes', {
|
|
425
|
-
'change_table' => 'extender_no_record',
|
|
426
|
-
'change_key' => 'id|1',
|
|
427
|
-
'change_type' => 'I',
|
|
428
|
-
'change_time' => Time.now
|
|
429
|
-
}
|
|
430
|
-
replicator.replicate_difference diff, 2
|
|
431
|
-
|
|
432
|
-
session.left.select_record(:table => "extender_no_record").should == {
|
|
433
|
-
'id' => 1,
|
|
434
|
-
'name' => 'blub'
|
|
435
|
-
}
|
|
436
|
-
ensure
|
|
437
|
-
Committers::NeverCommitter.rollback_current_session
|
|
438
|
-
if session
|
|
439
|
-
session.left.execute "delete from extender_no_record"
|
|
440
|
-
session.right.execute "delete from extender_no_record"
|
|
441
|
-
session.left.execute "delete from rr_pending_changes"
|
|
442
|
-
end
|
|
443
|
-
end
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
it "replicate_difference should handle inserts failing due the new record being deleted after the original diff was loaded" do
|
|
447
|
-
begin
|
|
448
|
-
config = deep_copy(standard_config)
|
|
449
|
-
config.options[:committer] = :never_commit
|
|
450
|
-
|
|
451
|
-
session = Session.new(config)
|
|
452
|
-
|
|
453
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
454
|
-
'change_table' => 'extender_no_record',
|
|
455
|
-
'change_key' => 'id|1',
|
|
456
|
-
'change_type' => 'I',
|
|
457
|
-
'change_time' => Time.now
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
461
|
-
helper = ReplicationHelper.new(rep_run)
|
|
462
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
463
|
-
|
|
464
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
465
|
-
diff.load
|
|
466
|
-
|
|
467
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
468
|
-
'change_table' => 'extender_no_record',
|
|
469
|
-
'change_key' => 'id|1',
|
|
470
|
-
'change_type' => 'D',
|
|
471
|
-
'change_time' => Time.now
|
|
472
|
-
}
|
|
473
|
-
replicator.replicate_difference diff, 2
|
|
474
|
-
|
|
475
|
-
# no rspec expectation: success is when we get till here without exception
|
|
476
|
-
ensure
|
|
477
|
-
Committers::NeverCommitter.rollback_current_session
|
|
478
|
-
session.left.execute "delete from rr_pending_changes" if session
|
|
479
|
-
end
|
|
480
|
-
end
|
|
481
|
-
|
|
482
|
-
it "replicate_difference should raise Exception if all replication attempts have been exceeded" do
|
|
483
|
-
rep_run = ReplicationRun.new Session.new, TaskSweeper.new(1)
|
|
484
|
-
helper = ReplicationHelper.new(rep_run)
|
|
485
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
486
|
-
lambda {replicator.replicate_difference :dummy_diff, 0}.
|
|
487
|
-
should raise_error(Exception, "max replication attempts exceeded")
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
it "replicate_difference should handle updates rejected by the database" do
|
|
491
|
-
begin
|
|
492
|
-
config = deep_copy(standard_config)
|
|
493
|
-
config.options[:committer] = :never_commit
|
|
494
|
-
config.options[:replication_conflict_handling] = :left_wins
|
|
495
|
-
|
|
496
|
-
session = Session.new(config)
|
|
497
|
-
session.left.execute "delete from rr_logged_events"
|
|
498
|
-
|
|
499
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
500
|
-
'change_table' => 'scanner_records',
|
|
501
|
-
'change_key' => 'id|1',
|
|
502
|
-
'change_new_key' => 'id|2',
|
|
503
|
-
'change_type' => 'U',
|
|
504
|
-
'change_time' => Time.now
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
508
|
-
helper = ReplicationHelper.new(rep_run)
|
|
509
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
510
|
-
|
|
511
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
512
|
-
diff.load
|
|
513
|
-
|
|
514
|
-
lambda {replicator.replicate_difference diff, 1}.should raise_error(/duplicate/i)
|
|
515
|
-
|
|
516
|
-
# Verify that the transaction has not become invalid
|
|
517
|
-
helper.log_replication_outcome diff, "bla", "blub"
|
|
518
|
-
|
|
519
|
-
row = session.left.select_one("select * from rr_logged_events")
|
|
520
|
-
row['change_table'].should == 'scanner_records'
|
|
521
|
-
row['change_key'].should == '1'
|
|
522
|
-
row['description'].should == 'bla'
|
|
523
|
-
|
|
524
|
-
ensure
|
|
525
|
-
Committers::NeverCommitter.rollback_current_session
|
|
526
|
-
if session
|
|
527
|
-
session.left.execute "delete from rr_pending_changes"
|
|
528
|
-
session.left.execute "delete from rr_logged_events"
|
|
529
|
-
end
|
|
530
|
-
end
|
|
531
|
-
end
|
|
532
|
-
|
|
533
|
-
it "replicate_difference should handle deletes rejected by the database" do
|
|
534
|
-
begin
|
|
535
|
-
config = deep_copy(standard_config)
|
|
536
|
-
config.options[:committer] = :never_commit
|
|
537
|
-
config.options[:replication_conflict_handling] = :left_wins
|
|
538
|
-
|
|
539
|
-
session = Session.new(config)
|
|
540
|
-
|
|
541
|
-
session.left.select_all("select * from rr_logged_events").should == []
|
|
542
|
-
|
|
543
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
544
|
-
'change_table' => 'referenced_table',
|
|
545
|
-
'change_key' => 'first_id|1|second_id|2',
|
|
546
|
-
'change_new_key' => nil,
|
|
547
|
-
'change_type' => 'D',
|
|
548
|
-
'change_time' => Time.now
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
552
|
-
helper = ReplicationHelper.new(rep_run)
|
|
553
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
554
|
-
|
|
555
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
556
|
-
diff.load
|
|
557
|
-
|
|
558
|
-
lambda {replicator.replicate_difference diff, 1}.should raise_error(/referencing_table_fkey/)
|
|
559
|
-
|
|
560
|
-
# Verify that the transaction has not become invalid
|
|
561
|
-
helper.log_replication_outcome diff, "bla", "blub"
|
|
562
|
-
|
|
563
|
-
row = session.left.select_one("select * from rr_logged_events")
|
|
564
|
-
row['change_table'].should == 'referenced_table'
|
|
565
|
-
row['change_key'].should =~ /first_id.*1.*second_id.*2/
|
|
566
|
-
row['description'].should == 'bla'
|
|
567
|
-
|
|
568
|
-
ensure
|
|
569
|
-
Committers::NeverCommitter.rollback_current_session
|
|
570
|
-
if session
|
|
571
|
-
session.left.execute "delete from rr_pending_changes"
|
|
572
|
-
session.left.execute "delete from rr_logged_events"
|
|
573
|
-
end
|
|
574
|
-
end
|
|
575
|
-
end
|
|
576
|
-
|
|
577
|
-
it "replicate_difference should handle deletes failing due to the target record vanishing" do
|
|
578
|
-
begin
|
|
579
|
-
config = deep_copy(standard_config)
|
|
580
|
-
config.options[:committer] = :never_commit
|
|
581
|
-
config.options[:replication_conflict_handling] = :left_wins
|
|
582
|
-
|
|
583
|
-
session = Session.new(config)
|
|
584
|
-
|
|
585
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
586
|
-
'change_table' => 'scanner_records',
|
|
587
|
-
'change_key' => 'id|3',
|
|
588
|
-
'change_new_key' => nil,
|
|
589
|
-
'change_type' => 'D',
|
|
590
|
-
'change_time' => Time.now
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
594
|
-
helper = ReplicationHelper.new(rep_run)
|
|
595
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
596
|
-
|
|
597
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
598
|
-
diff.load
|
|
599
|
-
|
|
600
|
-
session.right.insert_record 'rr_pending_changes', {
|
|
601
|
-
'change_table' => 'scanner_records',
|
|
602
|
-
'change_key' => 'id|3',
|
|
603
|
-
'change_new_key' => 'id|4',
|
|
604
|
-
'change_type' => 'U',
|
|
605
|
-
'change_time' => Time.now
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
replicator.replicate_difference diff, 2
|
|
609
|
-
|
|
610
|
-
session.right.select_one("select * from scanner_records where id = 4").
|
|
611
|
-
should be_nil
|
|
612
|
-
ensure
|
|
613
|
-
Committers::NeverCommitter.rollback_current_session
|
|
614
|
-
if session
|
|
615
|
-
session.left.execute "delete from rr_pending_changes"
|
|
616
|
-
session.left.execute "delete from rr_logged_events"
|
|
617
|
-
end
|
|
618
|
-
end
|
|
619
|
-
end
|
|
620
|
-
|
|
621
|
-
it "replicate_difference should handle updates failing due to the source record being deleted after the original diff was loaded" do
|
|
622
|
-
begin
|
|
623
|
-
config = deep_copy(standard_config)
|
|
624
|
-
config.options[:committer] = :never_commit
|
|
625
|
-
config.options[:replication_conflict_handling] = :left_wins
|
|
626
|
-
|
|
627
|
-
session = Session.new(config)
|
|
628
|
-
|
|
629
|
-
session.left.insert_record 'extender_no_record', {
|
|
630
|
-
'id' => '2',
|
|
631
|
-
'name' => 'bla'
|
|
632
|
-
}
|
|
633
|
-
session.right.insert_record 'extender_no_record', {
|
|
634
|
-
'id' => '2',
|
|
635
|
-
'name' => 'blub'
|
|
636
|
-
}
|
|
637
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
638
|
-
'change_table' => 'extender_no_record',
|
|
639
|
-
'change_key' => 'id|1',
|
|
640
|
-
'change_new_key' => 'id|2',
|
|
641
|
-
'change_type' => 'U',
|
|
642
|
-
'change_time' => Time.now
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
646
|
-
helper = ReplicationHelper.new(rep_run)
|
|
647
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
648
|
-
|
|
649
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
650
|
-
diff.load
|
|
651
|
-
|
|
652
|
-
session.left.delete_record 'extender_no_record', {'id' => '2'}
|
|
653
|
-
|
|
654
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
655
|
-
'change_table' => 'extender_no_record',
|
|
656
|
-
'change_key' => 'id|2',
|
|
657
|
-
'change_type' => 'D',
|
|
658
|
-
'change_time' => Time.now
|
|
659
|
-
}
|
|
660
|
-
replicator.replicate_difference diff, 2
|
|
661
|
-
|
|
662
|
-
session.right.select_one("select * from extender_no_record").should be_nil
|
|
663
|
-
ensure
|
|
664
|
-
Committers::NeverCommitter.rollback_current_session
|
|
665
|
-
if session
|
|
666
|
-
session.left.execute "delete from extender_no_record"
|
|
667
|
-
session.right.execute "delete from extender_no_record"
|
|
668
|
-
session.left.execute "delete from rr_pending_changes"
|
|
669
|
-
end
|
|
670
|
-
end
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
it "replicate_difference should handle updates failing due to the target record being deleted after the original diff was loaded" do
|
|
674
|
-
begin
|
|
675
|
-
config = deep_copy(standard_config)
|
|
676
|
-
config.options[:committer] = :never_commit
|
|
677
|
-
config.options[:replication_conflict_handling] = :left_wins
|
|
678
|
-
|
|
679
|
-
session = Session.new(config)
|
|
680
|
-
|
|
681
|
-
session.left.insert_record 'extender_no_record', {
|
|
682
|
-
'id' => '2',
|
|
683
|
-
'name' => 'bla'
|
|
684
|
-
}
|
|
685
|
-
session.left.insert_record 'rr_pending_changes', {
|
|
686
|
-
'change_table' => 'extender_no_record',
|
|
687
|
-
'change_key' => 'id|1',
|
|
688
|
-
'change_new_key' => 'id|2',
|
|
689
|
-
'change_type' => 'U',
|
|
690
|
-
'change_time' => Time.now
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
|
694
|
-
helper = ReplicationHelper.new(rep_run)
|
|
695
|
-
replicator = Replicators::TwoWayReplicator.new(helper)
|
|
696
|
-
|
|
697
|
-
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
|
698
|
-
diff.load
|
|
699
|
-
|
|
700
|
-
session.right.insert_record 'rr_pending_changes', {
|
|
701
|
-
'change_table' => 'extender_no_record',
|
|
702
|
-
'change_key' => 'id|1',
|
|
703
|
-
'change_type' => 'D',
|
|
704
|
-
'change_time' => Time.now
|
|
705
|
-
}
|
|
706
|
-
replicator.replicate_difference diff, 2
|
|
707
|
-
|
|
708
|
-
session.right.select_record(:table => "extender_no_record").should == {
|
|
709
|
-
'id' => 2,
|
|
710
|
-
'name' => 'bla'
|
|
711
|
-
}
|
|
712
|
-
ensure
|
|
713
|
-
Committers::NeverCommitter.rollback_current_session
|
|
714
|
-
if session
|
|
715
|
-
session.left.execute "delete from extender_no_record"
|
|
716
|
-
session.right.execute "delete from extender_no_record"
|
|
717
|
-
session.left.execute "delete from rr_pending_changes"
|
|
718
|
-
end
|
|
719
|
-
end
|
|
720
|
-
end
|
|
721
|
-
end
|