andyjeffries-rubyrep 1.2.1
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 +83 -0
- data/License.txt +20 -0
- data/Manifest.txt +151 -0
- data/README.txt +37 -0
- data/bin/rubyrep +8 -0
- data/lib/rubyrep.rb +72 -0
- data/lib/rubyrep/base_runner.rb +195 -0
- data/lib/rubyrep/command_runner.rb +144 -0
- data/lib/rubyrep/committers/buffered_committer.rb +151 -0
- data/lib/rubyrep/committers/committers.rb +152 -0
- data/lib/rubyrep/configuration.rb +275 -0
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +165 -0
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +65 -0
- data/lib/rubyrep/connection_extenders/mysql_extender.rb +59 -0
- data/lib/rubyrep/connection_extenders/postgresql_extender.rb +277 -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/log_helper.rb +30 -0
- data/lib/rubyrep/logged_change.rb +160 -0
- data/lib/rubyrep/logged_change_loader.rb +197 -0
- data/lib/rubyrep/noisy_connection.rb +80 -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 +431 -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 +100 -0
- data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
- data/lib/rubyrep/replication_extenders/postgresql_replication.rb +236 -0
- data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
- data/lib/rubyrep/replication_helper.rb +142 -0
- data/lib/rubyrep/replication_initializer.rb +327 -0
- data/lib/rubyrep/replication_run.rb +142 -0
- data/lib/rubyrep/replication_runner.rb +166 -0
- data/lib/rubyrep/replicators/replicators.rb +42 -0
- data/lib/rubyrep/replicators/two_way_replicator.rb +361 -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 +230 -0
- data/lib/rubyrep/sync_helper.rb +121 -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 +46 -0
- data/lib/rubyrep/table_sorter.rb +70 -0
- data/lib/rubyrep/table_spec_resolver.rb +142 -0
- data/lib/rubyrep/table_sync.rb +90 -0
- data/lib/rubyrep/task_sweeper.rb +77 -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 +93 -0
- data/lib/rubyrep/version.rb +9 -0
- data/rubyrep +8 -0
- data/rubyrep.bat +4 -0
- data/setup.rb +1585 -0
- data/spec/base_runner_spec.rb +218 -0
- data/spec/buffered_committer_spec.rb +274 -0
- data/spec/command_runner_spec.rb +145 -0
- data/spec/committers_spec.rb +178 -0
- data/spec/configuration_spec.rb +203 -0
- data/spec/connection_extender_interface_spec.rb +141 -0
- data/spec/connection_extenders_registration_spec.rb +164 -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/dolphins.jpg +0 -0
- data/spec/generate_runner_spec.rb +84 -0
- data/spec/initializer_spec.rb +46 -0
- data/spec/log_helper_spec.rb +39 -0
- data/spec/logged_change_loader_spec.rb +68 -0
- data/spec/logged_change_spec.rb +470 -0
- data/spec/noisy_connection_spec.rb +78 -0
- data/spec/postgresql_replication_spec.rb +48 -0
- data/spec/postgresql_schema_support_spec.rb +212 -0
- data/spec/postgresql_support_spec.rb +63 -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 +423 -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 +161 -0
- data/spec/replication_extender_interface_spec.rb +367 -0
- data/spec/replication_extenders_spec.rb +32 -0
- data/spec/replication_helper_spec.rb +178 -0
- data/spec/replication_initializer_spec.rb +509 -0
- data/spec/replication_run_spec.rb +443 -0
- data/spec/replication_runner_spec.rb +254 -0
- data/spec/replicators_spec.rb +36 -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 +253 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +305 -0
- data/spec/strange_name_support_spec.rb +135 -0
- data/spec/sync_helper_spec.rb +169 -0
- data/spec/sync_runner_spec.rb +78 -0
- data/spec/syncers_spec.rb +171 -0
- data/spec/table_scan_helper_spec.rb +36 -0
- data/spec/table_scan_spec.rb +49 -0
- data/spec/table_sorter_spec.rb +30 -0
- data/spec/table_spec_resolver_spec.rb +111 -0
- data/spec/table_sync_spec.rb +140 -0
- data/spec/task_sweeper_spec.rb +47 -0
- data/spec/trigger_mode_switcher_spec.rb +83 -0
- data/spec/two_way_replicator_spec.rb +721 -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 +93 -0
- metadata +190 -0
|
@@ -0,0 +1,36 @@
|
|
|
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 "configured_replicator should return the correct replicator" do
|
|
25
|
+
options = {:replicator => :two_way}
|
|
26
|
+
Replicators.configured_replicator(options).should == Replicators::TwoWayReplicator
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "register should register the provided replicator" do
|
|
30
|
+
Replicators.instance_variable_set :@replicators, nil
|
|
31
|
+
Replicators.register :a_key => :a
|
|
32
|
+
Replicators.register :b_key => :b
|
|
33
|
+
Replicators.replicators[:a_key].should == :a
|
|
34
|
+
Replicators.replicators[:b_key].should == :b
|
|
35
|
+
end
|
|
36
|
+
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
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
|
|
4
|
+
include RR
|
|
5
|
+
|
|
6
|
+
describe Session do # database connection caching is disabled
|
|
7
|
+
before(:each) do
|
|
8
|
+
Initializer.configuration = standard_config
|
|
9
|
+
@@old_cache_status = ConnectionExtenders.use_db_connection_cache(false)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
after(:each) do
|
|
13
|
+
ConnectionExtenders.use_db_connection_cache(@@old_cache_status)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "initialize should keep a reference of the Configuration object" do
|
|
17
|
+
mock_active_record :twice
|
|
18
|
+
|
|
19
|
+
session = Session.new(Initializer.configuration)
|
|
20
|
+
session.configuration.should == Initializer.configuration
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "initialize should establish the database connections" do
|
|
24
|
+
mock_active_record :twice
|
|
25
|
+
|
|
26
|
+
session = Session.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "'left=' should store a Connection object and 'left' should return it" do
|
|
30
|
+
mock_active_record :twice
|
|
31
|
+
|
|
32
|
+
session = Session.new
|
|
33
|
+
|
|
34
|
+
session.left = :dummy
|
|
35
|
+
session.left.should == :dummy
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "'right=' should store a Connection object and 'right' should return it" do
|
|
39
|
+
mock_active_record :twice
|
|
40
|
+
|
|
41
|
+
session = Session.new
|
|
42
|
+
|
|
43
|
+
session.right = :dummy
|
|
44
|
+
session.right.should == :dummy
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "initialize shouldn't create the same database connection twice" do
|
|
48
|
+
mock_active_record :once
|
|
49
|
+
|
|
50
|
+
Initializer.configuration = deep_copy(Initializer.configuration)
|
|
51
|
+
Initializer.configuration.right = Initializer.configuration.left.clone
|
|
52
|
+
|
|
53
|
+
session = Session.new
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe Session do # here database connection caching is _not_ disabled
|
|
58
|
+
before(:each) do
|
|
59
|
+
Initializer.configuration = standard_config
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
after(:each) do
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "initialize should create (fake) proxy connections as per configuration" do
|
|
66
|
+
dummy_proxy = Object.new
|
|
67
|
+
dummy_connection = mock("dummy connection")
|
|
68
|
+
dummy_connection.stub!(:tables).and_return([])
|
|
69
|
+
dummy_connection.stub!(:manual_primary_keys=)
|
|
70
|
+
dummy_connection.stub!(:select_one).and_return({'x' => '2'})
|
|
71
|
+
dummy_proxy.should_receive(:create_session).and_return(dummy_connection)
|
|
72
|
+
DRbObject.should_receive(:new).with(nil,"druby://localhost:9876").and_return(dummy_proxy)
|
|
73
|
+
|
|
74
|
+
session = Session.new proxied_config
|
|
75
|
+
|
|
76
|
+
session.proxies[:left].should == dummy_proxy
|
|
77
|
+
session.proxies[:right].should be_an_instance_of(DatabaseProxy)
|
|
78
|
+
|
|
79
|
+
session.left.should == dummy_connection
|
|
80
|
+
session.right.should be_an_instance_of(ProxyConnection)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "initialize should assign manual primary keys to the proxy connections" do
|
|
84
|
+
config = deep_copy(standard_config)
|
|
85
|
+
config.included_table_specs.clear
|
|
86
|
+
config.include_tables "table_with_manual_key, extender_without_key", :primary_key_names => ['id']
|
|
87
|
+
session = Session.new config
|
|
88
|
+
session.left.manual_primary_keys.should == {'table_with_manual_key'=>['id']}
|
|
89
|
+
session.right.manual_primary_keys.should == {'extender_without_key'=>['id']}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "refresh should reestablish the database connections if not active anymore" do
|
|
93
|
+
session = Session.new
|
|
94
|
+
session.right.destroy
|
|
95
|
+
session.right.connection.should_not be_active
|
|
96
|
+
lambda {session.right.select_one("select 1+1 as x")}.should raise_error
|
|
97
|
+
session.refresh
|
|
98
|
+
session.right.connection.should be_active
|
|
99
|
+
session.right.select_one("select 1+1 as x")['x'].to_i.should == 2
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "refresh should raise error even if database connect fails silently" do
|
|
103
|
+
session = Session.new
|
|
104
|
+
session.right.destroy
|
|
105
|
+
session.right.connection.should_not be_active
|
|
106
|
+
session.should_receive(:connect_database)
|
|
107
|
+
lambda {session.refresh}.should raise_error(/no connection to.*right.*database/)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "refresh should work with proxied database connections" do
|
|
111
|
+
ensure_proxy
|
|
112
|
+
session = Session.new(proxied_config)
|
|
113
|
+
session.right.destroy
|
|
114
|
+
session.right.connection.should_not be_active
|
|
115
|
+
lambda {session.right.select_one("select 1+1 as x")}.should raise_error
|
|
116
|
+
session.refresh
|
|
117
|
+
session.right.connection.should be_active
|
|
118
|
+
session.right.select_one("select 1+1 as x")['x'].to_i.should == 2
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "disconnect_databases should disconnect both databases" do
|
|
122
|
+
session = Session.new(standard_config)
|
|
123
|
+
session.left.connection.should be_active
|
|
124
|
+
old_right_connection = session.right.connection
|
|
125
|
+
old_right_connection.should be_active
|
|
126
|
+
session.disconnect_databases
|
|
127
|
+
session.left.should be_nil
|
|
128
|
+
session.right.should be_nil
|
|
129
|
+
old_right_connection.should_not be_active
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "refresh should not do anyting if the connection is still active" do
|
|
133
|
+
session = Session.new
|
|
134
|
+
old_connection_id = session.right.connection.object_id
|
|
135
|
+
session.refresh
|
|
136
|
+
session.right.connection.object_id.should == old_connection_id
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "refresh should replace active connections if forced is true" do
|
|
140
|
+
session = Session.new
|
|
141
|
+
old_connection_id = session.right.connection.object_id
|
|
142
|
+
session.refresh :forced => true
|
|
143
|
+
session.right.connection.object_id.should_not == old_connection_id
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "manual_primary_keys should return the specified manual primary keys" do
|
|
147
|
+
config = deep_copy(standard_config)
|
|
148
|
+
config.included_table_specs.clear
|
|
149
|
+
config.include_tables "table_with_manual_key, extender_without_key", :key => ['id']
|
|
150
|
+
session = Session.new config
|
|
151
|
+
session.manual_primary_keys(:left).should == {'table_with_manual_key'=>['id']}
|
|
152
|
+
session.manual_primary_keys(:right).should == {'extender_without_key'=>['id']}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "manual_primary_keys should accept keys that are not packed into an array" do
|
|
156
|
+
config = deep_copy(standard_config)
|
|
157
|
+
config.included_table_specs.clear
|
|
158
|
+
config.include_tables "table_with_manual_key", :key => 'id'
|
|
159
|
+
session = Session.new config
|
|
160
|
+
session.manual_primary_keys(:left).should == {'table_with_manual_key'=>['id']}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "manual_primary_keys should follow the :auto_key_limit option" do
|
|
164
|
+
config = deep_copy(standard_config)
|
|
165
|
+
config.included_table_specs.clear
|
|
166
|
+
config.include_tables "scanner_records"
|
|
167
|
+
config.include_tables "extender_without_key"
|
|
168
|
+
config.include_tables "table_with_manual_key", :key => 'id'
|
|
169
|
+
|
|
170
|
+
config.options[:auto_key_limit] = 2
|
|
171
|
+
session = Session.new config
|
|
172
|
+
session.manual_primary_keys(:left).should == {
|
|
173
|
+
'table_with_manual_key' => ['id'],
|
|
174
|
+
'extender_without_key' => ['first_id', 'second_id']
|
|
175
|
+
}
|
|
176
|
+
session.left.primary_key_names('extender_without_key').should == ['first_id', 'second_id']
|
|
177
|
+
|
|
178
|
+
config.options[:auto_key_limit] = 1
|
|
179
|
+
session = Session.new config
|
|
180
|
+
session.manual_primary_keys(:left).should == {
|
|
181
|
+
'table_with_manual_key' => ['id']
|
|
182
|
+
}
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "corresponding_table should return the correct corresponding table" do
|
|
186
|
+
config = deep_copy(standard_config)
|
|
187
|
+
config.included_table_specs.clear
|
|
188
|
+
config.include_tables "/scanner/"
|
|
189
|
+
config.include_tables "table_with_manual_key, extender_without_key"
|
|
190
|
+
session = Session.new config
|
|
191
|
+
|
|
192
|
+
session.corresponding_table(:left, 'scanner_records').should == 'scanner_records'
|
|
193
|
+
session.corresponding_table(:right, 'scanner_records').should == 'scanner_records'
|
|
194
|
+
session.corresponding_table(:left, 'table_with_manual_key').should == 'extender_without_key'
|
|
195
|
+
session.corresponding_table(:right, 'extender_without_key').should == 'table_with_manual_key'
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "corresponding_table should return the given table if no corresponding table can be found" do
|
|
199
|
+
session = Session.new
|
|
200
|
+
session.corresponding_table(:left, 'not_existing_table').should == 'not_existing_table'
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "configured_table_pairs should return the table pairs as per included_table_specs parameter" do
|
|
204
|
+
session = Session.new
|
|
205
|
+
session.configured_table_pairs(['scanner_records']).should == [
|
|
206
|
+
{:left => 'scanner_records', :right => 'scanner_records'},
|
|
207
|
+
]
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it "configured_table_pairs should return the table pairs as per configuration if included_table_specs paramter is an empty array" do
|
|
211
|
+
session = Session.new
|
|
212
|
+
session.configured_table_pairs([]).should == [
|
|
213
|
+
{:left => 'scanner_left_records_only', :right => 'scanner_left_records_only'},
|
|
214
|
+
{:left => 'table_with_manual_key', :right => 'table_with_manual_key'}
|
|
215
|
+
]
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def convert_table_array_to_table_pair_array(tables)
|
|
219
|
+
tables.map {|table| {:left => table, :right => table}}
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
it "sort_table_pairs should sort the tables correctly" do
|
|
223
|
+
table_pairs = convert_table_array_to_table_pair_array([
|
|
224
|
+
'scanner_records',
|
|
225
|
+
'referencing_table',
|
|
226
|
+
'referenced_table',
|
|
227
|
+
'scanner_text_key',
|
|
228
|
+
])
|
|
229
|
+
sorted_table_pairs = Session.new.sort_table_pairs(table_pairs)
|
|
230
|
+
|
|
231
|
+
# ensure result holds the original table pairs
|
|
232
|
+
p = Proc.new {|l, r| l[:left] <=> r[:left]}
|
|
233
|
+
sorted_table_pairs.sort(&p).should == table_pairs.sort(&p)
|
|
234
|
+
|
|
235
|
+
# make sure the referenced table comes before the referencing table
|
|
236
|
+
sorted_table_pairs.map {|table_pair| table_pair[:left]}.grep(/referenc/).
|
|
237
|
+
should == ['referenced_table', 'referencing_table']
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "sort_table_pairs should not sort the tables if table_ordering is not enabled in the configuration" do
|
|
241
|
+
table_pairs = convert_table_array_to_table_pair_array([
|
|
242
|
+
'scanner_records',
|
|
243
|
+
'referencing_table',
|
|
244
|
+
'referenced_table',
|
|
245
|
+
'scanner_text_key',
|
|
246
|
+
])
|
|
247
|
+
config = deep_copy(standard_config)
|
|
248
|
+
config.options[:table_ordering] = false
|
|
249
|
+
session = Session.new config
|
|
250
|
+
session.sort_table_pairs(table_pairs).should == table_pairs
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|