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.
Files changed (125) hide show
  1. data/History.txt +83 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +151 -0
  4. data/README.txt +37 -0
  5. data/bin/rubyrep +8 -0
  6. data/lib/rubyrep.rb +72 -0
  7. data/lib/rubyrep/base_runner.rb +195 -0
  8. data/lib/rubyrep/command_runner.rb +144 -0
  9. data/lib/rubyrep/committers/buffered_committer.rb +151 -0
  10. data/lib/rubyrep/committers/committers.rb +152 -0
  11. data/lib/rubyrep/configuration.rb +275 -0
  12. data/lib/rubyrep/connection_extenders/connection_extenders.rb +165 -0
  13. data/lib/rubyrep/connection_extenders/jdbc_extender.rb +65 -0
  14. data/lib/rubyrep/connection_extenders/mysql_extender.rb +59 -0
  15. data/lib/rubyrep/connection_extenders/postgresql_extender.rb +277 -0
  16. data/lib/rubyrep/database_proxy.rb +52 -0
  17. data/lib/rubyrep/direct_table_scan.rb +75 -0
  18. data/lib/rubyrep/generate_runner.rb +105 -0
  19. data/lib/rubyrep/initializer.rb +39 -0
  20. data/lib/rubyrep/log_helper.rb +30 -0
  21. data/lib/rubyrep/logged_change.rb +160 -0
  22. data/lib/rubyrep/logged_change_loader.rb +197 -0
  23. data/lib/rubyrep/noisy_connection.rb +80 -0
  24. data/lib/rubyrep/proxied_table_scan.rb +171 -0
  25. data/lib/rubyrep/proxy_block_cursor.rb +145 -0
  26. data/lib/rubyrep/proxy_connection.rb +431 -0
  27. data/lib/rubyrep/proxy_cursor.rb +44 -0
  28. data/lib/rubyrep/proxy_row_cursor.rb +43 -0
  29. data/lib/rubyrep/proxy_runner.rb +89 -0
  30. data/lib/rubyrep/replication_difference.rb +100 -0
  31. data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
  32. data/lib/rubyrep/replication_extenders/postgresql_replication.rb +236 -0
  33. data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
  34. data/lib/rubyrep/replication_helper.rb +142 -0
  35. data/lib/rubyrep/replication_initializer.rb +327 -0
  36. data/lib/rubyrep/replication_run.rb +142 -0
  37. data/lib/rubyrep/replication_runner.rb +166 -0
  38. data/lib/rubyrep/replicators/replicators.rb +42 -0
  39. data/lib/rubyrep/replicators/two_way_replicator.rb +361 -0
  40. data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
  41. data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
  42. data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
  43. data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
  44. data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
  45. data/lib/rubyrep/scan_runner.rb +25 -0
  46. data/lib/rubyrep/session.rb +230 -0
  47. data/lib/rubyrep/sync_helper.rb +121 -0
  48. data/lib/rubyrep/sync_runner.rb +31 -0
  49. data/lib/rubyrep/syncers/syncers.rb +112 -0
  50. data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
  51. data/lib/rubyrep/table_scan.rb +54 -0
  52. data/lib/rubyrep/table_scan_helper.rb +46 -0
  53. data/lib/rubyrep/table_sorter.rb +70 -0
  54. data/lib/rubyrep/table_spec_resolver.rb +142 -0
  55. data/lib/rubyrep/table_sync.rb +90 -0
  56. data/lib/rubyrep/task_sweeper.rb +77 -0
  57. data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
  58. data/lib/rubyrep/type_casting_cursor.rb +31 -0
  59. data/lib/rubyrep/uninstall_runner.rb +93 -0
  60. data/lib/rubyrep/version.rb +9 -0
  61. data/rubyrep +8 -0
  62. data/rubyrep.bat +4 -0
  63. data/setup.rb +1585 -0
  64. data/spec/base_runner_spec.rb +218 -0
  65. data/spec/buffered_committer_spec.rb +274 -0
  66. data/spec/command_runner_spec.rb +145 -0
  67. data/spec/committers_spec.rb +178 -0
  68. data/spec/configuration_spec.rb +203 -0
  69. data/spec/connection_extender_interface_spec.rb +141 -0
  70. data/spec/connection_extenders_registration_spec.rb +164 -0
  71. data/spec/database_proxy_spec.rb +48 -0
  72. data/spec/database_rake_spec.rb +40 -0
  73. data/spec/db_specific_connection_extenders_spec.rb +34 -0
  74. data/spec/db_specific_replication_extenders_spec.rb +38 -0
  75. data/spec/direct_table_scan_spec.rb +61 -0
  76. data/spec/dolphins.jpg +0 -0
  77. data/spec/generate_runner_spec.rb +84 -0
  78. data/spec/initializer_spec.rb +46 -0
  79. data/spec/log_helper_spec.rb +39 -0
  80. data/spec/logged_change_loader_spec.rb +68 -0
  81. data/spec/logged_change_spec.rb +470 -0
  82. data/spec/noisy_connection_spec.rb +78 -0
  83. data/spec/postgresql_replication_spec.rb +48 -0
  84. data/spec/postgresql_schema_support_spec.rb +212 -0
  85. data/spec/postgresql_support_spec.rb +63 -0
  86. data/spec/progress_bar_spec.rb +77 -0
  87. data/spec/proxied_table_scan_spec.rb +151 -0
  88. data/spec/proxy_block_cursor_spec.rb +197 -0
  89. data/spec/proxy_connection_spec.rb +423 -0
  90. data/spec/proxy_cursor_spec.rb +56 -0
  91. data/spec/proxy_row_cursor_spec.rb +66 -0
  92. data/spec/proxy_runner_spec.rb +70 -0
  93. data/spec/replication_difference_spec.rb +161 -0
  94. data/spec/replication_extender_interface_spec.rb +367 -0
  95. data/spec/replication_extenders_spec.rb +32 -0
  96. data/spec/replication_helper_spec.rb +178 -0
  97. data/spec/replication_initializer_spec.rb +509 -0
  98. data/spec/replication_run_spec.rb +443 -0
  99. data/spec/replication_runner_spec.rb +254 -0
  100. data/spec/replicators_spec.rb +36 -0
  101. data/spec/rubyrep_spec.rb +8 -0
  102. data/spec/scan_detail_reporter_spec.rb +119 -0
  103. data/spec/scan_progress_printers_spec.rb +68 -0
  104. data/spec/scan_report_printers_spec.rb +67 -0
  105. data/spec/scan_runner_spec.rb +50 -0
  106. data/spec/scan_summary_reporter_spec.rb +61 -0
  107. data/spec/session_spec.rb +253 -0
  108. data/spec/spec.opts +1 -0
  109. data/spec/spec_helper.rb +305 -0
  110. data/spec/strange_name_support_spec.rb +135 -0
  111. data/spec/sync_helper_spec.rb +169 -0
  112. data/spec/sync_runner_spec.rb +78 -0
  113. data/spec/syncers_spec.rb +171 -0
  114. data/spec/table_scan_helper_spec.rb +36 -0
  115. data/spec/table_scan_spec.rb +49 -0
  116. data/spec/table_sorter_spec.rb +30 -0
  117. data/spec/table_spec_resolver_spec.rb +111 -0
  118. data/spec/table_sync_spec.rb +140 -0
  119. data/spec/task_sweeper_spec.rb +47 -0
  120. data/spec/trigger_mode_switcher_spec.rb +83 -0
  121. data/spec/two_way_replicator_spec.rb +721 -0
  122. data/spec/two_way_syncer_spec.rb +256 -0
  123. data/spec/type_casting_cursor_spec.rb +50 -0
  124. data/spec/uninstall_runner_spec.rb +93 -0
  125. 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,8 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ # Time to add your specs!
4
+ # http://rspec.rubyforge.org/
5
+ describe "Place your specs here" do
6
+
7
+
8
+ 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
+