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,212 +0,0 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
-
|
|
3
|
-
include RR
|
|
4
|
-
|
|
5
|
-
require File.dirname(__FILE__) + "/../config/test_config.rb"
|
|
6
|
-
|
|
7
|
-
describe "PostgreSQL schema support" do
|
|
8
|
-
before(:each) do
|
|
9
|
-
config = deep_copy(standard_config)
|
|
10
|
-
config.options[:rep_prefix] = 'rx'
|
|
11
|
-
config.left[:schema_search_path] = 'rr'
|
|
12
|
-
config.right[:schema_search_path] = 'rr'
|
|
13
|
-
Initializer.configuration = config
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
after(:each) do
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
if Initializer.configuration.left[:adapter] == 'postgresql'
|
|
20
|
-
it "tables should show the tables from the schema and no others" do
|
|
21
|
-
session = Session.new
|
|
22
|
-
session.left.tables.include?('rr_simple').should be_true
|
|
23
|
-
session.left.tables.include?('scanner_records').should be_false
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "tables should not show the tables from other schemas" do
|
|
27
|
-
session = Session.new standard_config
|
|
28
|
-
session.left.tables.include?('scanner_records').should be_true
|
|
29
|
-
session.left.tables.include?('rr_simple').should be_false
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it "primary_key_names should work" do
|
|
33
|
-
session = Session.new
|
|
34
|
-
session.left.primary_key_names('rr_simple').should == ['id']
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "primary_key_names should pick the table in the target schema" do
|
|
38
|
-
session = Session.new
|
|
39
|
-
session.left.primary_key_names('rr_duplicate').should == ['id']
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "column_names should work" do
|
|
43
|
-
session = Session.new
|
|
44
|
-
session.left.column_names('rr_simple').should == ['id', 'name']
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "column_names should pick the table in the target schema" do
|
|
48
|
-
session = Session.new
|
|
49
|
-
session.left.column_names('rr_duplicate').should == ['id', 'name']
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "referenced_tables should work" do
|
|
53
|
-
session = Session.new
|
|
54
|
-
session.left.referenced_tables(['rr_referencing']).should == {
|
|
55
|
-
'rr_referencing' => ['rr_referenced']
|
|
56
|
-
}
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "table_select_query should work" do
|
|
60
|
-
session = Session.new
|
|
61
|
-
session.left.table_select_query('rr_simple').
|
|
62
|
-
should == 'select "id", "name" from "rr_simple" order by "id"'
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "TypeCastingCursor should work" do
|
|
66
|
-
session = Session.new
|
|
67
|
-
org_cursor = session.left.select_cursor(
|
|
68
|
-
:query => "select id, name from rr_simple where id = 1",
|
|
69
|
-
:type_cast => false
|
|
70
|
-
)
|
|
71
|
-
cursor = TypeCastingCursor.new session.left, 'rr_simple', org_cursor
|
|
72
|
-
|
|
73
|
-
row = cursor.next_row
|
|
74
|
-
|
|
75
|
-
row.should == {
|
|
76
|
-
'id' => 1,
|
|
77
|
-
'name' => 'bla'
|
|
78
|
-
}
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "sequence_values should pick the table in the target schema" do
|
|
82
|
-
session = Session.new
|
|
83
|
-
session.left.sequence_values('rx', 'rr_duplicate').keys.should == ["rr_duplicate_id_seq"]
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it "clear_sequence_setup should pick the table in the target schema" do
|
|
87
|
-
session = nil
|
|
88
|
-
begin
|
|
89
|
-
session = Session.new
|
|
90
|
-
initializer = ReplicationInitializer.new(session)
|
|
91
|
-
session.left.begin_db_transaction
|
|
92
|
-
session.right.begin_db_transaction
|
|
93
|
-
table_pair = {:left => 'rr_duplicate', :right => 'rr_duplicate'}
|
|
94
|
-
initializer.ensure_sequence_setup table_pair, 5, 2, 1
|
|
95
|
-
id1, id2 = get_example_sequence_values(session, 'rr_duplicate')
|
|
96
|
-
(id2 - id1).should == 5
|
|
97
|
-
(id1 % 5).should == 2
|
|
98
|
-
|
|
99
|
-
initializer.clear_sequence_setup :left, 'rr_duplicate'
|
|
100
|
-
id1, id2 = get_example_sequence_values(session, 'rr_duplicate')
|
|
101
|
-
(id2 - id1).should == 1
|
|
102
|
-
ensure
|
|
103
|
-
[:left, :right].each do |database|
|
|
104
|
-
initializer.clear_sequence_setup database, 'rr_duplicate' rescue nil if session
|
|
105
|
-
session.send(database).execute "delete from rr_duplicate" rescue nil if session
|
|
106
|
-
session.send(database).rollback_db_transaction rescue nil if session
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it "sequence setup should work" do
|
|
113
|
-
session = nil
|
|
114
|
-
begin
|
|
115
|
-
session = Session.new
|
|
116
|
-
initializer = ReplicationInitializer.new(session)
|
|
117
|
-
session.left.begin_db_transaction
|
|
118
|
-
session.right.begin_db_transaction
|
|
119
|
-
table_pair = {:left => 'rr_sequence_test', :right => 'rr_sequence_test'}
|
|
120
|
-
initializer.ensure_sequence_setup table_pair, 5, 2, 1
|
|
121
|
-
id1, id2 = get_example_sequence_values(session, 'rr_sequence_test')
|
|
122
|
-
(id2 - id1).should == 5
|
|
123
|
-
(id1 % 5).should == 2
|
|
124
|
-
ensure
|
|
125
|
-
[:left, :right].each do |database|
|
|
126
|
-
initializer.clear_sequence_setup database, 'rr_sequence_test' rescue nil if session
|
|
127
|
-
session.send(database).execute "delete from rr_sequence_test" rescue nil if session
|
|
128
|
-
session.send(database).rollback_db_transaction rescue nil if session
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
it "clear_sequence_setup should work" do
|
|
134
|
-
session = nil
|
|
135
|
-
begin
|
|
136
|
-
session = Session.new
|
|
137
|
-
initializer = ReplicationInitializer.new(session)
|
|
138
|
-
session.left.begin_db_transaction
|
|
139
|
-
session.right.begin_db_transaction
|
|
140
|
-
table_pair = {:left => 'rr_sequence_test', :right => 'rr_sequence_test'}
|
|
141
|
-
initializer.ensure_sequence_setup table_pair, 5, 2, 2
|
|
142
|
-
initializer.clear_sequence_setup :left, 'rr_sequence_test'
|
|
143
|
-
id1, id2 = get_example_sequence_values(session, 'rr_sequence_test')
|
|
144
|
-
(id2 - id1).should == 1
|
|
145
|
-
ensure
|
|
146
|
-
[:left, :right].each do |database|
|
|
147
|
-
initializer.clear_sequence_setup database, 'rr_sequence_test' if session
|
|
148
|
-
session.send(database).execute "delete from rr_sequence_test" if session
|
|
149
|
-
session.send(database).rollback_db_transaction if session
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
it "initializer should create tables in target schema" do
|
|
155
|
-
session = nil
|
|
156
|
-
begin
|
|
157
|
-
config = deep_copy(Initializer.configuration)
|
|
158
|
-
config.options[:rep_prefix] = 'ry'
|
|
159
|
-
session = Session.new config
|
|
160
|
-
session.left.begin_db_transaction
|
|
161
|
-
|
|
162
|
-
initializer = ReplicationInitializer.new(session)
|
|
163
|
-
initializer.create_change_log(:left)
|
|
164
|
-
|
|
165
|
-
# no exception ==> means table was created in target schema
|
|
166
|
-
session.left.select_one("select id from rr.ry_pending_changes")
|
|
167
|
-
ensure
|
|
168
|
-
session.left.rollback_db_transaction if session
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it "create_trigger, trigger_exists? and drop_trigger should work" do
|
|
173
|
-
session = nil
|
|
174
|
-
begin
|
|
175
|
-
session = Session.new
|
|
176
|
-
initializer = ReplicationInitializer.new(session)
|
|
177
|
-
session.left.begin_db_transaction
|
|
178
|
-
|
|
179
|
-
initializer.create_trigger :left, 'rr_trigger_test'
|
|
180
|
-
initializer.trigger_exists?(:left, 'rr_trigger_test').
|
|
181
|
-
should be_true
|
|
182
|
-
|
|
183
|
-
# Verify that the trigger can find the pending_changes table even if
|
|
184
|
-
# current search_path does not include it.
|
|
185
|
-
session.left.execute "set search_path = 'public'"
|
|
186
|
-
session.left.execute <<-EOF
|
|
187
|
-
insert into rr.rr_trigger_test(first_id, second_id) values(10, 11)
|
|
188
|
-
EOF
|
|
189
|
-
session.left.execute "set search_path = 'rr'"
|
|
190
|
-
session.left.select_one("select change_key from rx_pending_changes")['change_key'].
|
|
191
|
-
should == "first_id|10|second_id|11"
|
|
192
|
-
|
|
193
|
-
initializer.drop_trigger(:left, 'rr_trigger_test')
|
|
194
|
-
initializer.trigger_exists?(:left, 'rr_trigger_test').
|
|
195
|
-
should be_false
|
|
196
|
-
ensure
|
|
197
|
-
session.left.rollback_db_transaction if session
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
it "should work with complex search paths" do
|
|
202
|
-
config = deep_copy(standard_config)
|
|
203
|
-
config.left[:schema_search_path] = 'public,rr'
|
|
204
|
-
config.right[:schema_search_path] = 'public,rr'
|
|
205
|
-
session = Session.new(config)
|
|
206
|
-
|
|
207
|
-
tables = session.left.tables
|
|
208
|
-
tables.include?('rr_simple').should be_true
|
|
209
|
-
tables.include?('scanner_records').should be_true
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
end
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
-
|
|
3
|
-
include RR
|
|
4
|
-
|
|
5
|
-
require File.dirname(__FILE__) + "/../config/test_config.rb"
|
|
6
|
-
|
|
7
|
-
describe "PostgreSQL support" do
|
|
8
|
-
before(:each) do
|
|
9
|
-
Initializer.configuration = standard_config
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
after(:each) do
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
if Initializer.configuration.left[:adapter] == 'postgresql'
|
|
16
|
-
|
|
17
|
-
it "should read & write microsecond times" do
|
|
18
|
-
session = nil
|
|
19
|
-
begin
|
|
20
|
-
session = Session.new
|
|
21
|
-
session.left.begin_db_transaction
|
|
22
|
-
session.left.insert_record('extender_type_check',
|
|
23
|
-
{'id' => 2, 'timestamp' => Time.local(2009, "feb", 16, 20, 48, 1, 543)}
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
org_cursor = session.left.select_cursor(
|
|
27
|
-
:query => "select id, timestamp from extender_type_check where id = 2",
|
|
28
|
-
:type_cast => false
|
|
29
|
-
)
|
|
30
|
-
cursor = TypeCastingCursor.new session.left, 'extender_type_check', org_cursor
|
|
31
|
-
|
|
32
|
-
row = cursor.next_row
|
|
33
|
-
row['timestamp'].usec.should == 543
|
|
34
|
-
cursor.clear
|
|
35
|
-
ensure
|
|
36
|
-
session.left.rollback_db_transaction if session
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "should not round microsecond times to incorrect value" do
|
|
41
|
-
session = nil
|
|
42
|
-
begin
|
|
43
|
-
session = Session.new
|
|
44
|
-
session.left.begin_db_transaction
|
|
45
|
-
session.left.insert_record('extender_type_check',
|
|
46
|
-
{'id' => 2, 'timestamp' => Time.local(2009, "feb", 16, 13, 37, 11, 126291)}
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
org_cursor = session.left.select_cursor(
|
|
50
|
-
:query => "select id, timestamp from extender_type_check where id = 2",
|
|
51
|
-
:type_cast => false
|
|
52
|
-
)
|
|
53
|
-
cursor = TypeCastingCursor.new session.left, 'extender_type_check', org_cursor
|
|
54
|
-
|
|
55
|
-
row = cursor.next_row
|
|
56
|
-
row['timestamp'].usec.should == 126291
|
|
57
|
-
cursor.clear
|
|
58
|
-
ensure
|
|
59
|
-
session.left.rollback_db_transaction if session
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
data/spec/progress_bar_spec.rb
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
-
|
|
3
|
-
include RR
|
|
4
|
-
include ScanProgressPrinters
|
|
5
|
-
|
|
6
|
-
describe ProgressBar do
|
|
7
|
-
before(:each) do
|
|
8
|
-
@org_stdout = $stdout
|
|
9
|
-
$stdout = StringIO.new
|
|
10
|
-
@old_arg = ProgressBar.arg
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
after(:each) do
|
|
14
|
-
ProgressBar.arg = @old_arg
|
|
15
|
-
$stdout = @org_stdout
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it "arg should store the command line argument and max_markers return the correct marker number" do
|
|
19
|
-
ProgressBar.arg = nil
|
|
20
|
-
ProgressBar.new(100, Session.new(standard_config), 'bla', 'blub').max_markers.should == ProgressBar::MAX_MARKERS
|
|
21
|
-
ProgressBar.arg = "2"
|
|
22
|
-
ProgressBar.new(100, Session.new(standard_config), 'bla', 'blub').max_markers.should == 2
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "step should use ANSI codes if options :use_ansi is set" do
|
|
26
|
-
session = Session.new(deep_copy(standard_config))
|
|
27
|
-
session.configuration.options[:use_ansi] = true
|
|
28
|
-
bar = ProgressBar.new(10, session, 'bla', 'blub')
|
|
29
|
-
bar.step 1
|
|
30
|
-
bar.step 1
|
|
31
|
-
$stdout.string.should =~ Regexp.new(Regexp.escape("\e[1"))
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "step should not use ANSI codes if options :use_ansi is not true" do
|
|
35
|
-
session = Session.new(deep_copy(standard_config))
|
|
36
|
-
session.configuration.options[:use_ansi] = false
|
|
37
|
-
bar = ProgressBar.new(10, session, 'bla', 'blub')
|
|
38
|
-
bar.step 1
|
|
39
|
-
bar.step 1
|
|
40
|
-
$stdout.string.should_not =~ Regexp.new(Regexp.escape("\e[1"))
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it "should register itself with ScanRunner" do
|
|
44
|
-
RR::ScanProgressPrinters.printers[:progress_bar][:printer_class].
|
|
45
|
-
should == ProgressBar
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "step should print the correct progress" do
|
|
49
|
-
bar = ProgressBar.new(1000, Session.new(standard_config), 'bla', 'blub')
|
|
50
|
-
bar.step 200
|
|
51
|
-
bar.step 300
|
|
52
|
-
$stdout.string.count('.').should == ProgressBar::MAX_MARKERS / 2
|
|
53
|
-
bar.step 500
|
|
54
|
-
$stdout.string.count('.').should == ProgressBar::MAX_MARKERS
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it "step should work around weird floating point rounding issues" do
|
|
58
|
-
bar = ProgressBar.new(56, Session.new(standard_config), 'bla', 'blub')
|
|
59
|
-
(1..56).each {bar.step 1}
|
|
60
|
-
$stdout.string.count('.').should == ProgressBar::MAX_MARKERS
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "if max_steps is 0, any step call should go to 100% progress" do
|
|
64
|
-
config = deep_copy(standard_config)
|
|
65
|
-
config.options[:use_ansi] = true
|
|
66
|
-
bar = ProgressBar.new(0, Session.new(config), 'bla', 'blub')
|
|
67
|
-
bar.step
|
|
68
|
-
$stdout.string.count('.').should == ProgressBar::MAX_MARKERS
|
|
69
|
-
$stdout.string.should =~ /100%/
|
|
70
|
-
|
|
71
|
-
# Ensure we don't go over 100%
|
|
72
|
-
$stdout = StringIO.new
|
|
73
|
-
bar.step
|
|
74
|
-
$stdout.string.should == ''
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
end
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
-
|
|
3
|
-
include RR
|
|
4
|
-
|
|
5
|
-
describe ProxiedTableScan do
|
|
6
|
-
before(:each) do
|
|
7
|
-
Initializer.configuration = deep_copy(proxied_config)
|
|
8
|
-
|
|
9
|
-
# Small block size necessary to exercize all code paths in ProxiedTableScan
|
|
10
|
-
# even when only using tables with very small number of records.
|
|
11
|
-
Initializer.configuration.options[:proxy_block_size] = 2
|
|
12
|
-
|
|
13
|
-
ensure_proxy
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it "initialize should raise exception if session is not proxied" do
|
|
17
|
-
session = Session.new standard_config
|
|
18
|
-
lambda { ProxiedTableScan.new session, 'dummy_table' } \
|
|
19
|
-
.should raise_error(RuntimeError, /only works with proxied sessions/)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it "initialize should cache the primary keys" do
|
|
23
|
-
session = Session.new
|
|
24
|
-
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
25
|
-
scan.primary_key_names.should == ['id']
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it "initialize should raise exception if table doesn't have primary keys" do
|
|
29
|
-
session = Session.new
|
|
30
|
-
lambda {ProxiedTableScan.new session, 'extender_without_key'} \
|
|
31
|
-
.should raise_error(RuntimeError, /.*extender_without_key.*primary key/)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "block_size should return the :proxy_block_size value of the session options" do
|
|
35
|
-
ProxiedTableScan.new(Session.new, 'scanner_records').block_size \
|
|
36
|
-
.should == 2
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "block_size should return the matching table specific option if available" do
|
|
40
|
-
config = Initializer.configuration
|
|
41
|
-
old_table_specific_options = config.tables_with_options
|
|
42
|
-
begin
|
|
43
|
-
config.options = {:proxy_block_size => 2}
|
|
44
|
-
config.include_tables 'scanner_records', {:proxy_block_size => 3}
|
|
45
|
-
ProxiedTableScan.new(Session.new(config), 'scanner_records').block_size \
|
|
46
|
-
.should == 3
|
|
47
|
-
ensure
|
|
48
|
-
config.instance_eval {@tables_with_options = old_table_specific_options}
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Creates, prepares and returns a +ProxyBlockCursor+ for the given database
|
|
53
|
-
# +connection+ and +table+.
|
|
54
|
-
# Sets the ProxyBlockCursor#max_row_cache_size as per method parameter.
|
|
55
|
-
def get_block_cursor(connection, table, max_row_cache_size = 1000000)
|
|
56
|
-
cursor = ProxyBlockCursor.new connection, table
|
|
57
|
-
cursor.max_row_cache_size = max_row_cache_size
|
|
58
|
-
cursor.prepare_fetch
|
|
59
|
-
cursor.checksum :proxy_block_size => 1000
|
|
60
|
-
cursor
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "compare_blocks should compare all the records in the range" do
|
|
64
|
-
session = Session.new
|
|
65
|
-
|
|
66
|
-
left_cursor = get_block_cursor session.left, 'scanner_records'
|
|
67
|
-
right_cursor = get_block_cursor session.right, 'scanner_records'
|
|
68
|
-
|
|
69
|
-
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
70
|
-
diff = []
|
|
71
|
-
scan.compare_blocks(left_cursor, right_cursor) do |type, row|
|
|
72
|
-
diff.push [type, row]
|
|
73
|
-
end
|
|
74
|
-
# in this scenario the right table has the 'highest' data,
|
|
75
|
-
# so 'right-sided' data are already implicitely tested here
|
|
76
|
-
diff.should == [
|
|
77
|
-
[:conflict, [
|
|
78
|
-
{'id' => 2, 'name' => 'Bob - left database version'},
|
|
79
|
-
{'id' => 2, 'name' => 'Bob - right database version'}]],
|
|
80
|
-
[:left, {'id' => 3, 'name' => 'Charlie - exists in left database only'}],
|
|
81
|
-
[:right, {'id' => 4, 'name' => 'Dave - exists in right database only'}],
|
|
82
|
-
[:left, {'id' => 5, 'name' => 'Eve - exists in left database only'}],
|
|
83
|
-
[:right, {'id' => 6, 'name' => 'Fred - exists in right database only'}]
|
|
84
|
-
]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "compare_blocks should destroy the created cursors" do
|
|
88
|
-
session = Session.new
|
|
89
|
-
|
|
90
|
-
left_cursor = get_block_cursor session.left, 'scanner_records', 0
|
|
91
|
-
right_cursor = get_block_cursor session.right, 'scanner_records', 0
|
|
92
|
-
|
|
93
|
-
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
94
|
-
scan.compare_blocks(left_cursor, right_cursor) { |type, row| }
|
|
95
|
-
|
|
96
|
-
session.left.cursors.should == {}
|
|
97
|
-
session.right.cursors.should == {}
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it "run should only call compare single rows if there are different block checksums" do
|
|
101
|
-
config = deep_copy(proxied_config)
|
|
102
|
-
config.right = config.left
|
|
103
|
-
session = Session.new config
|
|
104
|
-
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
105
|
-
scan.should_not_receive(:compare_blocks)
|
|
106
|
-
diff = []
|
|
107
|
-
scan.run do |type, row|
|
|
108
|
-
diff.push [type,row]
|
|
109
|
-
end
|
|
110
|
-
diff.should == []
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it "run should compare all the records in the table" do
|
|
114
|
-
session = Session.new
|
|
115
|
-
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
116
|
-
diff = []
|
|
117
|
-
scan.run do |type, row|
|
|
118
|
-
diff.push [type, row]
|
|
119
|
-
end
|
|
120
|
-
# in this scenario the right table has the 'highest' data,
|
|
121
|
-
# so 'right-sided' data are already implicitely tested here
|
|
122
|
-
diff.should == [
|
|
123
|
-
[:conflict, [
|
|
124
|
-
{'id' => 2, 'name' => 'Bob - left database version'},
|
|
125
|
-
{'id' => 2, 'name' => 'Bob - right database version'}]],
|
|
126
|
-
[:left, {'id' => 3, 'name' => 'Charlie - exists in left database only'}],
|
|
127
|
-
[:right, {'id' => 4, 'name' => 'Dave - exists in right database only'}],
|
|
128
|
-
[:left, {'id' => 5, 'name' => 'Eve - exists in left database only'}],
|
|
129
|
-
[:right, {'id' => 6, 'name' => 'Fred - exists in right database only'}]
|
|
130
|
-
]
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
it "run should update the progress" do
|
|
134
|
-
session = Session.new
|
|
135
|
-
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
136
|
-
number_steps = 0
|
|
137
|
-
scan.should_receive(:update_progress).any_number_of_times do |steps|
|
|
138
|
-
number_steps += steps
|
|
139
|
-
end
|
|
140
|
-
scan.run {|_, _|}
|
|
141
|
-
number_steps.should == 8
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
it "run should update the progress even if there are no records" do
|
|
145
|
-
# it should do that to ensure the progress bar is printed
|
|
146
|
-
scan = ProxiedTableScan.new Session.new, 'extender_no_record'
|
|
147
|
-
scan.should_receive(:update_progress).at_least(:once)
|
|
148
|
-
scan.run {|_, _|}
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
-
|
|
3
|
-
include RR
|
|
4
|
-
|
|
5
|
-
describe ProxyBlockCursor do
|
|
6
|
-
before(:each) do
|
|
7
|
-
@session = create_mock_proxy_connection 'dummy_table', ['dummy_id']
|
|
8
|
-
@cursor = ProxyBlockCursor.new @session, 'dummy_table'
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it "initialize should super to ProxyCursor" do
|
|
12
|
-
@cursor.table.should == 'dummy_table'
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "next? should return true if there is an already loaded unprocessed row" do
|
|
16
|
-
@cursor.last_row = :dummy_row
|
|
17
|
-
@cursor.next?.should be_true
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it "next? should return true if the database cursor has more rows" do
|
|
21
|
-
table_cursor = mock("DBCursor")
|
|
22
|
-
table_cursor.should_receive(:next?).and_return(true)
|
|
23
|
-
@cursor.cursor = table_cursor
|
|
24
|
-
|
|
25
|
-
@cursor.next?.should be_true
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it "next? should return false if there are no loaded or unloaded unprocessed rows" do
|
|
29
|
-
table_cursor = mock("DBCursor")
|
|
30
|
-
table_cursor.should_receive(:next?).and_return(false)
|
|
31
|
-
@cursor.cursor = table_cursor
|
|
32
|
-
|
|
33
|
-
@cursor.next?.should be_false
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it "next_row should return last loaded unprocessed row or nil if there is none" do
|
|
37
|
-
@cursor.last_row = :dummy_row
|
|
38
|
-
|
|
39
|
-
@cursor.next_row.should == :dummy_row
|
|
40
|
-
@cursor.last_row.should be_nil
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it "next_row should return next row in database if there is no loaded unprocessed row available" do
|
|
44
|
-
table_cursor = mock("DBCursor")
|
|
45
|
-
table_cursor.should_receive(:next_row).and_return(:dummy_row)
|
|
46
|
-
@cursor.cursor = table_cursor
|
|
47
|
-
|
|
48
|
-
@cursor.next_row.should == :dummy_row
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it "reset_checksum should create a new empty SHA1 digest" do
|
|
52
|
-
@cursor.digest = :dummy_digest
|
|
53
|
-
@cursor.reset_checksum
|
|
54
|
-
@cursor.digest.should be_an_instance_of(Digest::SHA1)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it "reset_checksum should reset block variables" do
|
|
58
|
-
@cursor.reset_checksum
|
|
59
|
-
@cursor.row_checksums.should == []
|
|
60
|
-
@cursor.current_row_cache_size.should == 0
|
|
61
|
-
@cursor.row_cache.should == {}
|
|
62
|
-
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "update_checksum should update the existing digests" do
|
|
66
|
-
dummy_row1 = {'dummy_id' => 'dummy_value1'}
|
|
67
|
-
dummy_row2 = {'dummy_id' => 'dummy_value2'}
|
|
68
|
-
|
|
69
|
-
@cursor.reset_checksum
|
|
70
|
-
@cursor.update_checksum dummy_row1
|
|
71
|
-
@cursor.update_checksum dummy_row2
|
|
72
|
-
|
|
73
|
-
@cursor.current_checksum.should == Digest::SHA1.hexdigest(Marshal.dump(dummy_row1) + Marshal.dump(dummy_row2))
|
|
74
|
-
@cursor.row_checksums.should == [
|
|
75
|
-
{:row_keys => dummy_row1, :checksum => Digest::SHA1.hexdigest(Marshal.dump(dummy_row1))},
|
|
76
|
-
{:row_keys => dummy_row2, :checksum => Digest::SHA1.hexdigest(Marshal.dump(dummy_row2))},
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
@cursor.row_cache.should == {
|
|
80
|
-
Digest::SHA1.hexdigest(Marshal.dump(dummy_row1)) => Marshal.dump(dummy_row1),
|
|
81
|
-
Digest::SHA1.hexdigest(Marshal.dump(dummy_row2)) => Marshal.dump(dummy_row2)
|
|
82
|
-
}
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it "retrieve_row_cache should retrieve the specified elements" do
|
|
86
|
-
@cursor.row_cache = {'dummy_checksum' => 'bla'}
|
|
87
|
-
@cursor.retrieve_row_cache(['non_cached_row_checksum', 'dummy_checksum']).should ==
|
|
88
|
-
{'dummy_checksum' => 'bla'}
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
it "current_checksum should return the current checksum" do
|
|
92
|
-
digest = mock("Digest")
|
|
93
|
-
digest.should_receive(:hexdigest).and_return(:dummy_checksum)
|
|
94
|
-
@cursor.digest = digest
|
|
95
|
-
|
|
96
|
-
@cursor.current_checksum.should == :dummy_checksum
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it "checksum should reset the current digest" do
|
|
100
|
-
@cursor.reset_checksum # need to call it now so that for the call to checksum it can be mocked
|
|
101
|
-
@cursor.should_receive(:reset_checksum)
|
|
102
|
-
@cursor.should_receive(:next?).and_return(false)
|
|
103
|
-
@cursor.checksum :proxy_block_size => 1
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it "checksum should complain if neither :proxy_block_size nor :max_row are provided" do
|
|
107
|
-
lambda {@cursor.checksum}.should raise_error(
|
|
108
|
-
RuntimeError, 'options must include either :proxy_block_size or :max_row')
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
it "checksum should verify options" do
|
|
112
|
-
lambda {@cursor.checksum}.should raise_error(
|
|
113
|
-
RuntimeError, 'options must include either :proxy_block_size or :max_row')
|
|
114
|
-
lambda {@cursor.checksum(:proxy_block_size => 0)}.should raise_error(
|
|
115
|
-
RuntimeError, ':proxy_block_size must be greater than 0')
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it "checksum should read maximum :proxy_block_size rows" do
|
|
119
|
-
session = ProxyConnection.new proxied_config.left
|
|
120
|
-
|
|
121
|
-
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
122
|
-
cursor.prepare_fetch
|
|
123
|
-
|
|
124
|
-
last_row, = cursor.checksum :proxy_block_size => 2
|
|
125
|
-
last_row.should == {'id' => 2}
|
|
126
|
-
|
|
127
|
-
last_row, = cursor.checksum :proxy_block_size => 1000
|
|
128
|
-
last_row.should == {'id' => 5}
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it "checksum should read up to the specified :max_row" do
|
|
132
|
-
session = ProxyConnection.new proxied_config.left
|
|
133
|
-
|
|
134
|
-
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
135
|
-
cursor.prepare_fetch
|
|
136
|
-
|
|
137
|
-
last_row, = cursor.checksum :max_row => {'id' => 2}
|
|
138
|
-
last_row.should == {'id' => 2}
|
|
139
|
-
last_row, = cursor.checksum :max_row => {'id' => 1000}
|
|
140
|
-
last_row.should == {'id' => 5}
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
it "checksum called with :proxy_block_size should return the correct checksum" do
|
|
144
|
-
session = ProxyConnection.new proxied_config.left
|
|
145
|
-
|
|
146
|
-
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
147
|
-
cursor.prepare_fetch
|
|
148
|
-
|
|
149
|
-
last_row , checksum = cursor.checksum :proxy_block_size => 2
|
|
150
|
-
|
|
151
|
-
expected_checksum = Digest::SHA1.hexdigest(
|
|
152
|
-
Marshal.dump('id' => 1, 'name' => 'Alice - exists in both databases') +
|
|
153
|
-
Marshal.dump('id' => 2, 'name' => 'Bob - left database version')
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
checksum.should == expected_checksum
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
it "checksum called with :max_row should return the correct checksum" do
|
|
160
|
-
session = ProxyConnection.new proxied_config.left
|
|
161
|
-
|
|
162
|
-
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
163
|
-
cursor.prepare_fetch
|
|
164
|
-
|
|
165
|
-
last_row , checksum = cursor.checksum :max_row => {'id' => 2}
|
|
166
|
-
|
|
167
|
-
expected_checksum = Digest::SHA1.hexdigest(
|
|
168
|
-
Marshal.dump('id' => 1, 'name' => 'Alice - exists in both databases') +
|
|
169
|
-
Marshal.dump('id' => 2, 'name' => 'Bob - left database version')
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
checksum.should == expected_checksum
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
it "checksum called with :proxy_block_size should return the correct row count" do
|
|
176
|
-
session = ProxyConnection.new proxied_config.left
|
|
177
|
-
|
|
178
|
-
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
179
|
-
cursor.prepare_fetch
|
|
180
|
-
|
|
181
|
-
_ , _, row_count = cursor.checksum :proxy_block_size => 2
|
|
182
|
-
|
|
183
|
-
row_count.should == 2
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
it "checksum called with :max_row should return the correct row count" do
|
|
187
|
-
session = ProxyConnection.new proxied_config.left
|
|
188
|
-
|
|
189
|
-
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
190
|
-
cursor.prepare_fetch
|
|
191
|
-
|
|
192
|
-
_ , _, row_count = cursor.checksum :max_row => {'id' => 2}
|
|
193
|
-
|
|
194
|
-
row_count.should == 2
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
end
|