rubyrep 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +137 -0
- data/README.txt +37 -0
- data/Rakefile +30 -0
- data/bin/rubyrep +8 -0
- data/config/hoe.rb +72 -0
- data/config/mysql_config.rb +25 -0
- data/config/postgres_config.rb +21 -0
- data/config/proxied_test_config.rb +14 -0
- data/config/redmine_config.rb +17 -0
- data/config/rep_config.rb +20 -0
- data/config/requirements.rb +32 -0
- data/config/test_config.rb +20 -0
- data/lib/rubyrep/base_runner.rb +195 -0
- data/lib/rubyrep/command_runner.rb +144 -0
- data/lib/rubyrep/committers/buffered_committer.rb +140 -0
- data/lib/rubyrep/committers/committers.rb +146 -0
- data/lib/rubyrep/configuration.rb +240 -0
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +133 -0
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +284 -0
- data/lib/rubyrep/connection_extenders/mysql_extender.rb +168 -0
- data/lib/rubyrep/connection_extenders/postgresql_extender.rb +261 -0
- data/lib/rubyrep/database_proxy.rb +52 -0
- data/lib/rubyrep/direct_table_scan.rb +75 -0
- data/lib/rubyrep/generate_runner.rb +105 -0
- data/lib/rubyrep/initializer.rb +39 -0
- data/lib/rubyrep/logged_change.rb +326 -0
- data/lib/rubyrep/proxied_table_scan.rb +171 -0
- data/lib/rubyrep/proxy_block_cursor.rb +145 -0
- data/lib/rubyrep/proxy_connection.rb +318 -0
- data/lib/rubyrep/proxy_cursor.rb +44 -0
- data/lib/rubyrep/proxy_row_cursor.rb +43 -0
- data/lib/rubyrep/proxy_runner.rb +89 -0
- data/lib/rubyrep/replication_difference.rb +91 -0
- data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
- data/lib/rubyrep/replication_extenders/postgresql_replication.rb +204 -0
- data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
- data/lib/rubyrep/replication_helper.rb +104 -0
- data/lib/rubyrep/replication_initializer.rb +307 -0
- data/lib/rubyrep/replication_run.rb +48 -0
- data/lib/rubyrep/replication_runner.rb +138 -0
- data/lib/rubyrep/replicators/replicators.rb +37 -0
- data/lib/rubyrep/replicators/two_way_replicator.rb +334 -0
- data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
- data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
- data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
- data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
- data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
- data/lib/rubyrep/scan_runner.rb +25 -0
- data/lib/rubyrep/session.rb +177 -0
- data/lib/rubyrep/sync_helper.rb +111 -0
- data/lib/rubyrep/sync_runner.rb +31 -0
- data/lib/rubyrep/syncers/syncers.rb +112 -0
- data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
- data/lib/rubyrep/table_scan.rb +54 -0
- data/lib/rubyrep/table_scan_helper.rb +38 -0
- data/lib/rubyrep/table_sorter.rb +70 -0
- data/lib/rubyrep/table_spec_resolver.rb +136 -0
- data/lib/rubyrep/table_sync.rb +68 -0
- data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
- data/lib/rubyrep/type_casting_cursor.rb +31 -0
- data/lib/rubyrep/uninstall_runner.rb +92 -0
- data/lib/rubyrep/version.rb +9 -0
- data/lib/rubyrep.rb +68 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/sims/performance/big_rep_spec.rb +100 -0
- data/sims/performance/big_scan_spec.rb +57 -0
- data/sims/performance/big_sync_spec.rb +141 -0
- data/sims/performance/performance.rake +228 -0
- data/sims/sim_helper.rb +24 -0
- data/spec/base_runner_spec.rb +218 -0
- data/spec/buffered_committer_spec.rb +271 -0
- data/spec/command_runner_spec.rb +145 -0
- data/spec/committers_spec.rb +174 -0
- data/spec/configuration_spec.rb +198 -0
- data/spec/connection_extender_interface_spec.rb +138 -0
- data/spec/connection_extenders_registration_spec.rb +129 -0
- data/spec/database_proxy_spec.rb +48 -0
- data/spec/database_rake_spec.rb +40 -0
- data/spec/db_specific_connection_extenders_spec.rb +34 -0
- data/spec/db_specific_replication_extenders_spec.rb +38 -0
- data/spec/direct_table_scan_spec.rb +61 -0
- data/spec/generate_runner_spec.rb +84 -0
- data/spec/initializer_spec.rb +46 -0
- data/spec/logged_change_spec.rb +480 -0
- data/spec/postgresql_replication_spec.rb +48 -0
- data/spec/postgresql_support_spec.rb +57 -0
- data/spec/progress_bar_spec.rb +77 -0
- data/spec/proxied_table_scan_spec.rb +151 -0
- data/spec/proxy_block_cursor_spec.rb +197 -0
- data/spec/proxy_connection_spec.rb +399 -0
- data/spec/proxy_cursor_spec.rb +56 -0
- data/spec/proxy_row_cursor_spec.rb +66 -0
- data/spec/proxy_runner_spec.rb +70 -0
- data/spec/replication_difference_spec.rb +160 -0
- data/spec/replication_extender_interface_spec.rb +365 -0
- data/spec/replication_extenders_spec.rb +32 -0
- data/spec/replication_helper_spec.rb +121 -0
- data/spec/replication_initializer_spec.rb +477 -0
- data/spec/replication_run_spec.rb +166 -0
- data/spec/replication_runner_spec.rb +213 -0
- data/spec/replicators_spec.rb +31 -0
- data/spec/rubyrep_spec.rb +8 -0
- data/spec/scan_detail_reporter_spec.rb +119 -0
- data/spec/scan_progress_printers_spec.rb +68 -0
- data/spec/scan_report_printers_spec.rb +67 -0
- data/spec/scan_runner_spec.rb +50 -0
- data/spec/scan_summary_reporter_spec.rb +61 -0
- data/spec/session_spec.rb +212 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +295 -0
- data/spec/sync_helper_spec.rb +157 -0
- data/spec/sync_runner_spec.rb +78 -0
- data/spec/syncers_spec.rb +171 -0
- data/spec/table_scan_helper_spec.rb +29 -0
- data/spec/table_scan_spec.rb +49 -0
- data/spec/table_sorter_spec.rb +31 -0
- data/spec/table_spec_resolver_spec.rb +102 -0
- data/spec/table_sync_spec.rb +84 -0
- data/spec/trigger_mode_switcher_spec.rb +83 -0
- data/spec/two_way_replicator_spec.rb +551 -0
- data/spec/two_way_syncer_spec.rb +256 -0
- data/spec/type_casting_cursor_spec.rb +50 -0
- data/spec/uninstall_runner_spec.rb +86 -0
- data/tasks/database.rake +439 -0
- data/tasks/deployment.rake +29 -0
- data/tasks/environment.rake +9 -0
- data/tasks/java.rake +37 -0
- data/tasks/redmine_test.rake +47 -0
- data/tasks/rspec.rake +68 -0
- data/tasks/rubyrep.tailor +18 -0
- data/tasks/stats.rake +19 -0
- data/tasks/task_helper.rb +20 -0
- data.tar.gz.sig +0 -0
- metadata +243 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ReplicationRunner do
|
|
6
|
+
before(:each) do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should register itself with CommandRunner" do
|
|
10
|
+
CommandRunner.commands['replicate'][:command].should == ReplicationRunner
|
|
11
|
+
CommandRunner.commands['replicate'][:description].should be_an_instance_of(String)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "process_options should make options as nil and teturn status as 1 if command line parameters are unknown" do
|
|
15
|
+
# also verify that an error message is printed
|
|
16
|
+
$stderr.should_receive(:puts).any_number_of_times
|
|
17
|
+
runner = ReplicationRunner.new
|
|
18
|
+
status = runner.process_options ["--nonsense"]
|
|
19
|
+
runner.options.should == nil
|
|
20
|
+
status.should == 1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "process_options should make options as nil and return status as 1 if config option is not given" do
|
|
24
|
+
# also verify that an error message is printed
|
|
25
|
+
$stderr.should_receive(:puts).any_number_of_times
|
|
26
|
+
runner = ReplicationRunner.new
|
|
27
|
+
status = runner.process_options []
|
|
28
|
+
runner.options.should == nil
|
|
29
|
+
status.should == 1
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "process_options should make options as nil and return status as 0 if command line includes '--help'" do
|
|
33
|
+
# also verify that the help message is printed
|
|
34
|
+
$stderr.should_receive(:puts)
|
|
35
|
+
runner = ReplicationRunner.new
|
|
36
|
+
status = runner.process_options ["--help"]
|
|
37
|
+
runner.options.should == nil
|
|
38
|
+
status.should == 0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "process_options should set the correct options" do
|
|
42
|
+
runner = ReplicationRunner.new
|
|
43
|
+
runner.process_options ["-c", "config_path"]
|
|
44
|
+
runner.options[:config_file].should == 'config_path'
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "run should not start a replication if the command line is invalid" do
|
|
48
|
+
$stderr.should_receive(:puts).any_number_of_times
|
|
49
|
+
ReplicationRunner.any_instance_should_not_receive(:execute) {
|
|
50
|
+
ReplicationRunner.run(["--nonsense"])
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "run should start a replication if the command line is correct" do
|
|
55
|
+
ReplicationRunner.any_instance_should_receive(:execute) {
|
|
56
|
+
ReplicationRunner.run(["--config=path"])
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "session should create and return the session" do
|
|
61
|
+
runner = ReplicationRunner.new
|
|
62
|
+
runner.options = {:config_file => "config/test_config.rb"}
|
|
63
|
+
runner.session.should be_an_instance_of(Session)
|
|
64
|
+
runner.session.should == runner.session # should only be created one time
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "pause_replication should not pause if next replication is already overdue" do
|
|
68
|
+
runner = ReplicationRunner.new
|
|
69
|
+
runner.stub!(:session).and_return(Session.new(standard_config))
|
|
70
|
+
waiter_thread = mock('waiter_thread')
|
|
71
|
+
waiter_thread.should_not_receive(:join)
|
|
72
|
+
runner.instance_variable_set(:@waiter_thread, waiter_thread)
|
|
73
|
+
|
|
74
|
+
runner.pause_replication # verify no wait during first run
|
|
75
|
+
runner.instance_variable_set(:@last_run, 1.hour.ago)
|
|
76
|
+
runner.pause_replication # verify no wait if overdue
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "pause_replication should pause for correct time frame" do
|
|
80
|
+
runner = ReplicationRunner.new
|
|
81
|
+
runner.stub!(:session).and_return(Session.new(deep_copy(standard_config)))
|
|
82
|
+
runner.session.configuration.stub!(:options).and_return(:replication_interval => 2)
|
|
83
|
+
waiter_thread = mock('waiter_thread')
|
|
84
|
+
runner.instance_variable_set(:@waiter_thread, waiter_thread)
|
|
85
|
+
|
|
86
|
+
now = Time.now
|
|
87
|
+
Time.stub!(:now).and_return(now)
|
|
88
|
+
runner.instance_variable_set(:@last_run, now - 1.seconds)
|
|
89
|
+
waiter_thread.should_receive(:join).and_return {|time| time.to_f.should be_close(1.0, 0.01); 0}
|
|
90
|
+
|
|
91
|
+
runner.pause_replication
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "init_waiter should setup correct TERM signal processing" do
|
|
95
|
+
runner = ReplicationRunner.new
|
|
96
|
+
runner.stub!(:session).and_return(Session.new(standard_config))
|
|
97
|
+
|
|
98
|
+
# simulate sending the TERM signal
|
|
99
|
+
Signal.should_receive(:trap).with('TERM').and_yield
|
|
100
|
+
|
|
101
|
+
runner.init_waiter
|
|
102
|
+
|
|
103
|
+
# verify the that any pause would have been prematurely finished and
|
|
104
|
+
# termination signal been set
|
|
105
|
+
runner.termination_requested.should be_true
|
|
106
|
+
runner.instance_variable_get(:@waiter_thread).should_not be_alive
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "prepare_replication should call ReplicationInitializer#prepare_replication" do
|
|
110
|
+
runner = ReplicationRunner.new
|
|
111
|
+
runner.stub!(:session).and_return(:dummy_session)
|
|
112
|
+
initializer = mock('replication_initializer')
|
|
113
|
+
initializer.should_receive(:prepare_replication)
|
|
114
|
+
ReplicationInitializer.should_receive(:new).with(:dummy_session).and_return(initializer)
|
|
115
|
+
runner.prepare_replication
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Checks a specified number of times with specified waiting period between
|
|
119
|
+
# attempts if a given SQL query returns records.
|
|
120
|
+
# Returns +true+ if a record was found
|
|
121
|
+
# * +session+: an active Session object
|
|
122
|
+
# * +database+: either :+left+ or :+right+
|
|
123
|
+
# * +query+: sql query to execute
|
|
124
|
+
# * +max_attempts+: number of attempts to find the record
|
|
125
|
+
# * +interval+: waiting time in seconds between attempts
|
|
126
|
+
def check_for_record(session, database, query, max_attempts, interval)
|
|
127
|
+
found = false
|
|
128
|
+
|
|
129
|
+
max_attempts.times do
|
|
130
|
+
found = !!session.send(database).select_one(query)
|
|
131
|
+
break if found
|
|
132
|
+
sleep interval
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
found
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "execute should catch and print exceptions" do
|
|
139
|
+
org_stderr = $stderr
|
|
140
|
+
$stderr = StringIO.new
|
|
141
|
+
begin
|
|
142
|
+
session = Session.new
|
|
143
|
+
runner = ReplicationRunner.new
|
|
144
|
+
runner.stub!(:session).and_return(session)
|
|
145
|
+
runner.stub!(:init_waiter)
|
|
146
|
+
runner.stub!(:prepare_replication)
|
|
147
|
+
runner.stub!(:pause_replication)
|
|
148
|
+
runner.should_receive(:termination_requested).twice.and_return(false, true)
|
|
149
|
+
|
|
150
|
+
session.should_receive(:refresh).and_return {raise "refresh failed"}
|
|
151
|
+
|
|
152
|
+
runner.execute
|
|
153
|
+
|
|
154
|
+
$stderr.string.should =~ /Exception caught.*refresh failed/
|
|
155
|
+
$stderr.string.should =~ /replication_runner.rb:[0-9]+:in/
|
|
156
|
+
ensure
|
|
157
|
+
$stderr = org_stderr
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "execute should start the replication" do
|
|
162
|
+
config = deep_copy(standard_config)
|
|
163
|
+
config.options[:committer] = :buffered_commit
|
|
164
|
+
config.options[:replication_interval] = 0.01
|
|
165
|
+
|
|
166
|
+
# reset table selection
|
|
167
|
+
config.included_table_specs.replace ['scanner_left_records_only']
|
|
168
|
+
config.tables_with_options.clear
|
|
169
|
+
|
|
170
|
+
session = Session.new config
|
|
171
|
+
org_stdout = $stdout
|
|
172
|
+
begin
|
|
173
|
+
$stdout = StringIO.new
|
|
174
|
+
runner = ReplicationRunner.new
|
|
175
|
+
runner.process_options ["-c", "./config/test_config.rb"]
|
|
176
|
+
runner.stub!(:session).and_return(session)
|
|
177
|
+
|
|
178
|
+
t = Thread.new {runner.execute}
|
|
179
|
+
|
|
180
|
+
# verify that the initial sync is done
|
|
181
|
+
found = check_for_record(
|
|
182
|
+
session, :right,
|
|
183
|
+
"select * from scanner_left_records_only where id = 1",
|
|
184
|
+
100, 0.01
|
|
185
|
+
)
|
|
186
|
+
t.should be_alive # verify that the replication thread didn't die
|
|
187
|
+
found.should be_true
|
|
188
|
+
|
|
189
|
+
session.left.execute "insert into scanner_left_records_only(name) values('bla')"
|
|
190
|
+
|
|
191
|
+
# verify that the replication works
|
|
192
|
+
check_for_record(
|
|
193
|
+
session, :right,
|
|
194
|
+
"select * from scanner_left_records_only where name = 'bla'",
|
|
195
|
+
100, 0.01
|
|
196
|
+
).should be_true
|
|
197
|
+
|
|
198
|
+
runner.instance_variable_set(:@termination_requested, true)
|
|
199
|
+
t.join
|
|
200
|
+
ensure
|
|
201
|
+
$stdout = org_stdout
|
|
202
|
+
initializer = ReplicationInitializer.new session
|
|
203
|
+
[:left, :right].each do |database|
|
|
204
|
+
initializer.clear_sequence_setup database, 'scanner_left_records_only'
|
|
205
|
+
if initializer.trigger_exists?(database, 'scanner_left_records_only')
|
|
206
|
+
initializer.drop_trigger database, 'scanner_left_records_only'
|
|
207
|
+
end
|
|
208
|
+
session.send(database).execute "delete from scanner_left_records_only where name = 'bla'"
|
|
209
|
+
end
|
|
210
|
+
session.right.execute "delete from scanner_left_records_only"
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe Replicators do
|
|
6
|
+
before(:each) do
|
|
7
|
+
@old_replicators = Replicators.replicators
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
after(:each) do
|
|
11
|
+
Replicators.instance_variable_set :@replicators, @old_replicators
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "replicators should return empty hash if nil" do
|
|
15
|
+
Replicators.instance_variable_set :@replicators, nil
|
|
16
|
+
Replicators.replicators.should == {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "replicators should return the registered replicators" do
|
|
20
|
+
Replicators.instance_variable_set :@replicators, :dummy_data
|
|
21
|
+
Replicators.replicators.should == :dummy_data
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "register should register the provided replicator" do
|
|
25
|
+
Replicators.instance_variable_set :@replicators, nil
|
|
26
|
+
Replicators.register :a_key => :a
|
|
27
|
+
Replicators.register :b_key => :b
|
|
28
|
+
Replicators.replicators[:a_key].should == :a
|
|
29
|
+
Replicators.replicators[:b_key].should == :b
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ScanReportPrinters::ScanDetailReporter do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
$stdout.should_receive(:puts).any_number_of_times
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should register itself with ScanRunner" do
|
|
12
|
+
RR::ScanReportPrinters.printers.any? do |printer|
|
|
13
|
+
printer[:printer_class] == ScanReportPrinters::ScanDetailReporter
|
|
14
|
+
end.should be_true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "initialize should store the provided session" do
|
|
18
|
+
ScanReportPrinters::ScanDetailReporter.new(:dummy_session, nil).session.should == :dummy_session
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "scan should print the summary and the dump of the differences if mode = 'full'" do
|
|
22
|
+
org_stdout = $stdout
|
|
23
|
+
$stdout = StringIO.new
|
|
24
|
+
begin
|
|
25
|
+
reporter = ScanReportPrinters::ScanDetailReporter.new(nil, 'full')
|
|
26
|
+
|
|
27
|
+
# set some existing scan result to ensure it gets reset before the next run
|
|
28
|
+
reporter.scan_result = {:conflict => 0, :left => 0, :right => 1}
|
|
29
|
+
|
|
30
|
+
reporter.scan('left_table', 'right_table') do
|
|
31
|
+
reporter.report_difference :conflict, :dummy_row
|
|
32
|
+
reporter.report_difference :left, :dummy_row
|
|
33
|
+
reporter.report_difference :right, :dummy_row
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# verify summary
|
|
37
|
+
$stdout.string.should =~ /left_table \/ right_table [\.\s]*3\n/
|
|
38
|
+
|
|
39
|
+
# verify dump
|
|
40
|
+
io = StringIO.new($stdout.string.gsub(/^.*left_table.*$/, ''))
|
|
41
|
+
dump_objects = []
|
|
42
|
+
YAML.load_documents(io) do |yl|
|
|
43
|
+
dump_objects << yl
|
|
44
|
+
end
|
|
45
|
+
dump_objects.should == [
|
|
46
|
+
{:conflict=>:dummy_row},
|
|
47
|
+
{:left=>:dummy_row},
|
|
48
|
+
{:right=>:dummy_row}
|
|
49
|
+
]
|
|
50
|
+
ensure
|
|
51
|
+
$stdout = org_stdout
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "scan should print the summary and the keys of the differences if mode = 'keys'" do
|
|
56
|
+
org_stdout = $stdout
|
|
57
|
+
$stdout = StringIO.new
|
|
58
|
+
begin
|
|
59
|
+
session = Session.new
|
|
60
|
+
reporter = ScanReportPrinters::ScanDetailReporter.new(session, 'keys')
|
|
61
|
+
|
|
62
|
+
# set some existing scan result to ensure it gets reset before the next run
|
|
63
|
+
reporter.scan_result = {:conflict => 0, :left => 0, :right => 1}
|
|
64
|
+
|
|
65
|
+
reporter.scan('scanner_records', 'scanner_records') do
|
|
66
|
+
reporter.report_difference :conflict, [{'id' => 1, 'name' => 'bla'}, {'id' => 1, 'name' => 'blub'}]
|
|
67
|
+
reporter.report_difference :left, {'id' => 2, 'name' => 'bla'}
|
|
68
|
+
reporter.report_difference :right, {'id' => 3, 'name' => 'blub'}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
io = StringIO.new($stdout.string.gsub(/^.*scanner_records.*$/, ''))
|
|
72
|
+
dump_objects = []
|
|
73
|
+
YAML.load_documents(io) do |yl|
|
|
74
|
+
dump_objects << yl
|
|
75
|
+
end
|
|
76
|
+
dump_objects.should == [
|
|
77
|
+
{:conflict=>{"id"=>1}},
|
|
78
|
+
{:left=>{"id"=>2}},
|
|
79
|
+
{:right=>{"id"=>3}}
|
|
80
|
+
]
|
|
81
|
+
ensure
|
|
82
|
+
$stdout = org_stdout
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "scan should print the summary and the differing columns of the differences if mode = 'diff'" do
|
|
87
|
+
org_stdout = $stdout
|
|
88
|
+
$stdout = StringIO.new
|
|
89
|
+
begin
|
|
90
|
+
session = Session.new
|
|
91
|
+
reporter = ScanReportPrinters::ScanDetailReporter.new(session, 'diff')
|
|
92
|
+
|
|
93
|
+
# set some existing scan result to ensure it gets reset before the next run
|
|
94
|
+
reporter.scan_result = {:conflict => 0, :left => 0, :right => 1}
|
|
95
|
+
|
|
96
|
+
reporter.scan('scanner_records', 'scanner_records') do
|
|
97
|
+
reporter.report_difference :conflict, [
|
|
98
|
+
{'id' => 1, 'name' => 'bla', 'age' => 20},
|
|
99
|
+
{'id' => 1, 'name' => 'blub', 'age' => 20}
|
|
100
|
+
]
|
|
101
|
+
reporter.report_difference :left, {'id' => 2, 'name' => 'bla'}
|
|
102
|
+
reporter.report_difference :right, {'id' => 3, 'name' => 'blub'}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
io = StringIO.new($stdout.string.gsub(/^.*scanner_records.*$/, ''))
|
|
106
|
+
dump_objects = []
|
|
107
|
+
YAML.load_documents(io) do |yl|
|
|
108
|
+
dump_objects << yl
|
|
109
|
+
end
|
|
110
|
+
dump_objects.should == [
|
|
111
|
+
{:conflict=>[{'id' => 1, 'name' => 'bla'}, {'id' => 1, 'name' => 'blub'}]},
|
|
112
|
+
{:left=>{"name"=>"bla", "id"=>2}},
|
|
113
|
+
{:right=>{"name"=>"blub", "id"=>3}}
|
|
114
|
+
]
|
|
115
|
+
ensure
|
|
116
|
+
$stdout = org_stdout
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ScanProgressPrinters do
|
|
6
|
+
before(:each) do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "report_printers should an empty hash if there are no registered printers" do
|
|
10
|
+
org_printers = ScanProgressPrinters.printers
|
|
11
|
+
begin
|
|
12
|
+
ScanProgressPrinters.instance_eval { class_variable_set :@@progress_printers, nil }
|
|
13
|
+
ScanProgressPrinters.printers.should == {}
|
|
14
|
+
ensure
|
|
15
|
+
ScanProgressPrinters.instance_eval { class_variable_set :@@progress_printers, org_printers }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "register_printer should store the provided printers, printers should return them" do
|
|
20
|
+
org_printers = ScanProgressPrinters.printers
|
|
21
|
+
begin
|
|
22
|
+
ScanProgressPrinters.instance_eval { class_variable_set :@@progress_printers, nil }
|
|
23
|
+
ScanProgressPrinters.register :dummy_printer_id, :dummy_printer_class, "-d", "--dummy"
|
|
24
|
+
ScanProgressPrinters.register :another_printer_id, :another_printer_class, "-t"
|
|
25
|
+
ScanProgressPrinters.printers.should == {
|
|
26
|
+
:dummy_printer_id => {
|
|
27
|
+
:printer_class => :dummy_printer_class,
|
|
28
|
+
:opts => ["-d", "--dummy"]
|
|
29
|
+
},
|
|
30
|
+
:another_printer_id => {
|
|
31
|
+
:printer_class => :another_printer_class,
|
|
32
|
+
:opts => ["-t"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
ensure
|
|
36
|
+
ScanProgressPrinters.instance_eval { class_variable_set :@@progress_printers, org_printers }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "on_printer_selection should create and yield the correct printer" do
|
|
41
|
+
org_printers = ScanProgressPrinters.printers
|
|
42
|
+
begin
|
|
43
|
+
ScanProgressPrinters.instance_eval { class_variable_set :@@progress_printers, nil }
|
|
44
|
+
|
|
45
|
+
# register a printer which will not be selected in the command line options
|
|
46
|
+
printer_x_class = mock("printer_x")
|
|
47
|
+
printer_x_class.should_not_receive :arg=
|
|
48
|
+
ScanProgressPrinters.register :printer_x_id, printer_x_class, "-x", "--printer_x"
|
|
49
|
+
|
|
50
|
+
# register a printer that will be selected in the command line options
|
|
51
|
+
printer_y_class = mock("printer_y")
|
|
52
|
+
printer_y_class.should_receive(:arg=).with("dummy_arg")
|
|
53
|
+
|
|
54
|
+
ScanProgressPrinters.register :printer_y_id, printer_y_class, "-y", "--printer_y[=arg]", "description"
|
|
55
|
+
|
|
56
|
+
selected_printer = nil
|
|
57
|
+
parser = OptionParser.new
|
|
58
|
+
ScanProgressPrinters.on_printer_selection(parser) do |printer|
|
|
59
|
+
selected_printer = printer
|
|
60
|
+
end
|
|
61
|
+
parser.parse!(["--printer_y=dummy_arg"])
|
|
62
|
+
|
|
63
|
+
selected_printer.should == printer_y_class
|
|
64
|
+
ensure
|
|
65
|
+
ScanProgressPrinters.instance_eval { class_variable_set :@@progress_printers, org_printers }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ScanReportPrinters do
|
|
6
|
+
before(:each) do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "report_printers should an empty array if there are no registered printers" do
|
|
10
|
+
org_printers = ScanReportPrinters.printers
|
|
11
|
+
begin
|
|
12
|
+
ScanReportPrinters.instance_eval { class_variable_set :@@report_printers, nil }
|
|
13
|
+
ScanReportPrinters.printers.should == []
|
|
14
|
+
ensure
|
|
15
|
+
ScanReportPrinters.instance_eval { class_variable_set :@@report_printers, org_printers }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "register_printer should store the provided printers, report_printer should return them" do
|
|
20
|
+
org_printers = ScanReportPrinters.printers
|
|
21
|
+
begin
|
|
22
|
+
ScanReportPrinters.instance_eval { class_variable_set :@@report_printers, nil }
|
|
23
|
+
ScanReportPrinters.register :dummy_printer_class, "-d", "--dummy"
|
|
24
|
+
ScanReportPrinters.register :another_printer_class, "-t"
|
|
25
|
+
ScanReportPrinters.printers.should == [
|
|
26
|
+
{ :printer_class => :dummy_printer_class,
|
|
27
|
+
:opts => ["-d", "--dummy"]
|
|
28
|
+
},
|
|
29
|
+
{ :printer_class => :another_printer_class,
|
|
30
|
+
:opts => ["-t"]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
ensure
|
|
34
|
+
ScanReportPrinters.instance_eval { class_variable_set :@@report_printers, org_printers }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "on_printer_selection should create and yield the printer class and option argument" do
|
|
39
|
+
org_printers = ScanReportPrinters.printers
|
|
40
|
+
begin
|
|
41
|
+
ScanReportPrinters.instance_eval { class_variable_set :@@report_printers, nil }
|
|
42
|
+
|
|
43
|
+
# register a printer class which will not be selected in the command line options
|
|
44
|
+
printer_x = mock("printer_x")
|
|
45
|
+
ScanReportPrinters.register printer_x, "-x", "--printer_x"
|
|
46
|
+
|
|
47
|
+
# register a printer class that will be selected in the command line options
|
|
48
|
+
printer_y = mock("printer_y")
|
|
49
|
+
|
|
50
|
+
ScanReportPrinters.register printer_y, "-y", "--printer_y[=arg]", "description"
|
|
51
|
+
|
|
52
|
+
selected_printer_class = nil
|
|
53
|
+
selected_arg = nil
|
|
54
|
+
parser = OptionParser.new
|
|
55
|
+
ScanReportPrinters.on_printer_selection(parser) do |printer_class, arg|
|
|
56
|
+
selected_printer_class = printer_class
|
|
57
|
+
selected_arg = arg
|
|
58
|
+
end
|
|
59
|
+
parser.parse!(["--printer_y=dummy_arg"])
|
|
60
|
+
|
|
61
|
+
selected_printer_class.should == printer_y
|
|
62
|
+
selected_arg.should == 'dummy_arg'
|
|
63
|
+
ensure
|
|
64
|
+
ScanReportPrinters.instance_eval { class_variable_set :@@report_printers, org_printers }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ScanRunner do
|
|
6
|
+
before(:each) do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should register itself with CommandRunner" do
|
|
10
|
+
CommandRunner.commands['scan'][:command].should == ScanRunner
|
|
11
|
+
CommandRunner.commands['scan'][:description].should be_an_instance_of(String)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "execute should scan the specified tables" do
|
|
15
|
+
org_stdout = $stdout
|
|
16
|
+
$stdout = StringIO.new
|
|
17
|
+
begin
|
|
18
|
+
Initializer.configuration = Configuration.new
|
|
19
|
+
scan_runner = ScanRunner.new
|
|
20
|
+
scan_runner.options = {
|
|
21
|
+
:config_file => "#{File.dirname(__FILE__)}/../config/test_config.rb",
|
|
22
|
+
:table_specs => ["scanner_records", "extender_one_record"]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
scan_runner.execute
|
|
26
|
+
|
|
27
|
+
$stdout.string.should =~ /scanner_records.* 5\n/
|
|
28
|
+
$stdout.string.should =~ /extender_one_record.* 0\n/
|
|
29
|
+
ensure
|
|
30
|
+
$stdout = org_stdout
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "create_processor should create the correct table scanner" do
|
|
35
|
+
scan_runner = ScanRunner.new
|
|
36
|
+
dummy_scan_class = mock("scan class")
|
|
37
|
+
dummy_scan_class.should_receive(:new).
|
|
38
|
+
with(:dummy_session, "left_table", "right_table").
|
|
39
|
+
and_return(:dummy_table_scanner)
|
|
40
|
+
TableScanHelper.should_receive(:scan_class).with(:dummy_session).
|
|
41
|
+
and_return(dummy_scan_class)
|
|
42
|
+
scan_runner.should_receive(:session).any_number_of_times.and_return(:dummy_session)
|
|
43
|
+
scan_runner.create_processor("left_table", "right_table").
|
|
44
|
+
should == :dummy_table_scanner
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "summary_description should return a description" do
|
|
48
|
+
ScanRunner.new.summary_description.should be_an_instance_of(String)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ScanReportPrinters::ScanSummaryReporter do
|
|
6
|
+
before(:each) do
|
|
7
|
+
$stdout.should_receive(:puts).any_number_of_times
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should register itself with ScanRunner" do
|
|
11
|
+
RR::ScanReportPrinters.printers.any? do |printer|
|
|
12
|
+
printer[:printer_class] == ScanReportPrinters::ScanSummaryReporter
|
|
13
|
+
end.should be_true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "initialize should detect if the detailed number of differnces should be counted" do
|
|
17
|
+
ScanReportPrinters::ScanSummaryReporter.new(nil, nil).only_totals.should be_true
|
|
18
|
+
ScanReportPrinters::ScanSummaryReporter.new(nil, "bla").only_totals.should be_true
|
|
19
|
+
ScanReportPrinters::ScanSummaryReporter.new(nil, "detailed").only_totals.should be_false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "scan should count differences correctly in totals mode" do
|
|
23
|
+
org_stdout = $stdout
|
|
24
|
+
$stdout = StringIO.new
|
|
25
|
+
begin
|
|
26
|
+
reporter = ScanReportPrinters::ScanSummaryReporter.new(nil, nil)
|
|
27
|
+
|
|
28
|
+
# set some existing scan result to ensure it gets reset before the next run
|
|
29
|
+
reporter.scan_result = {:conflict => 0, :left => 0, :right => 1}
|
|
30
|
+
|
|
31
|
+
reporter.scan('left_table', 'right_table') do
|
|
32
|
+
reporter.report_difference :conflict, :dummy_row
|
|
33
|
+
reporter.report_difference :left, :dummy_row
|
|
34
|
+
reporter.report_difference :right, :dummy_row
|
|
35
|
+
end
|
|
36
|
+
$stdout.string.should =~ /left_table \/ right_table [\.\s]*3\n/
|
|
37
|
+
ensure
|
|
38
|
+
$stdout = org_stdout
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "scan should count differences correctly in detailed mode" do
|
|
43
|
+
org_stdout = $stdout
|
|
44
|
+
$stdout = StringIO.new
|
|
45
|
+
begin
|
|
46
|
+
reporter = ScanReportPrinters::ScanSummaryReporter.new(nil, "detailed")
|
|
47
|
+
|
|
48
|
+
reporter.scan('left_table', 'left_table') do
|
|
49
|
+
reporter.report_difference :conflict, :dummy_row
|
|
50
|
+
reporter.report_difference :left, :dummy_row
|
|
51
|
+
reporter.report_difference :left, :dummy_row
|
|
52
|
+
reporter.report_difference :right, :dummy_row
|
|
53
|
+
reporter.report_difference :right, :dummy_row
|
|
54
|
+
reporter.report_difference :right, :dummy_row
|
|
55
|
+
end
|
|
56
|
+
$stdout.string.should =~ /left_table\s+1\s+2\s+3\n/
|
|
57
|
+
ensure
|
|
58
|
+
$stdout = org_stdout
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|