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,61 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe DirectTableScan do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "run should compare all the records in the table" do
|
|
11
|
+
session = Session.new
|
|
12
|
+
scan = DirectTableScan.new session, 'scanner_records'
|
|
13
|
+
diff = []
|
|
14
|
+
scan.run do |type, row|
|
|
15
|
+
diff.push [type, row]
|
|
16
|
+
end
|
|
17
|
+
# in this scenario the right table has the 'highest' data,
|
|
18
|
+
# so 'right-sided' data are already implicitely tested here
|
|
19
|
+
diff.should == [
|
|
20
|
+
[:conflict, [
|
|
21
|
+
{'id' => 2, 'name' => 'Bob - left database version'},
|
|
22
|
+
{'id' => 2, 'name' => 'Bob - right database version'}]],
|
|
23
|
+
[:left, {'id' => 3, 'name' => 'Charlie - exists in left database only'}],
|
|
24
|
+
[:right, {'id' => 4, 'name' => 'Dave - exists in right database only'}],
|
|
25
|
+
[:left, {'id' => 5, 'name' => 'Eve - exists in left database only'}],
|
|
26
|
+
[:right, {'id' => 6, 'name' => 'Fred - exists in right database only'}]
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "run should handle one-sided data" do
|
|
31
|
+
# separate test case for left-sided data; right-sided data are already covered in the general test
|
|
32
|
+
session = Session.new
|
|
33
|
+
scan = DirectTableScan.new session, 'scanner_left_records_only'
|
|
34
|
+
diff = []
|
|
35
|
+
scan.run do |type, row|
|
|
36
|
+
diff.push [type, row]
|
|
37
|
+
end
|
|
38
|
+
diff.should == [
|
|
39
|
+
[:left, {'id' => 1, 'name' => 'Alice'}],
|
|
40
|
+
[:left, {'id' => 2, 'name' => 'Bob'}]
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "run should update the progress" do
|
|
45
|
+
session = Session.new
|
|
46
|
+
scan = DirectTableScan.new session, 'scanner_records'
|
|
47
|
+
number_steps = 0
|
|
48
|
+
scan.should_receive(:update_progress).any_number_of_times do |steps|
|
|
49
|
+
number_steps += steps
|
|
50
|
+
end
|
|
51
|
+
scan.run {|_, _|}
|
|
52
|
+
number_steps.should == 8
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "run should update the progress even if there are no records" do
|
|
56
|
+
# it should do that to ensure the progress bar is printed
|
|
57
|
+
scan = DirectTableScan.new Session.new, 'extender_no_record'
|
|
58
|
+
scan.should_receive(:update_progress).at_least(:once)
|
|
59
|
+
scan.run {|_, _|}
|
|
60
|
+
end
|
|
61
|
+
end
|
data/spec/dolphins.jpg
ADDED
|
Binary file
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe GenerateRunner do
|
|
6
|
+
before(:each) do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should register itself with CommandRunner" do
|
|
10
|
+
CommandRunner.commands['generate'][:command].should == GenerateRunner
|
|
11
|
+
CommandRunner.commands['generate'][: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 = GenerateRunner.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 file name is not given" do
|
|
24
|
+
# also verify that an error message is printed
|
|
25
|
+
$stderr.should_receive(:puts).any_number_of_times
|
|
26
|
+
runner = GenerateRunner.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 = GenerateRunner.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 = GenerateRunner.new
|
|
43
|
+
runner.process_options ["my_file_name"]
|
|
44
|
+
runner.options[:file_name].should == 'my_file_name'
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "run should not start the generate command if the command line is invalid" do
|
|
48
|
+
$stderr.should_receive(:puts).any_number_of_times
|
|
49
|
+
GenerateRunner.any_instance_should_not_receive(:execute) {
|
|
50
|
+
GenerateRunner.run(["--nonsense"])
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "run should start an uninstall if the command line is correct" do
|
|
55
|
+
GenerateRunner.any_instance_should_receive(:execute) {
|
|
56
|
+
GenerateRunner.run(["my_file_name"])
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "execute should refuse to overwrite an existing file" do
|
|
61
|
+
begin
|
|
62
|
+
File.open("my_config_template", 'w') do |f|
|
|
63
|
+
f.write 'bla'
|
|
64
|
+
end
|
|
65
|
+
runner = GenerateRunner.new
|
|
66
|
+
runner.options = {:file_name => 'my_config_template'}
|
|
67
|
+
lambda {runner.execute}.should raise_error(/refuse/)
|
|
68
|
+
ensure
|
|
69
|
+
File.delete('my_config_template') rescue nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "execute should create the configuration template under the specified name" do
|
|
74
|
+
begin
|
|
75
|
+
runner = GenerateRunner.new
|
|
76
|
+
runner.options = {:file_name => 'my_config_template'}
|
|
77
|
+
runner.execute
|
|
78
|
+
File.exists?('my_config_template').should be_true
|
|
79
|
+
ensure
|
|
80
|
+
File.delete 'my_config_template' rescue nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe Initializer do
|
|
6
|
+
it "should have an empty configuration" do
|
|
7
|
+
Initializer::configuration.should be_an_instance_of(Configuration)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe Initializer do
|
|
12
|
+
before(:each) do
|
|
13
|
+
Initializer::reset
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "run should yield the configuration object" do
|
|
17
|
+
Initializer::run do |config|
|
|
18
|
+
config.should be_an_instance_of(Configuration)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def make_dummy_configuration_change
|
|
23
|
+
Initializer::run do |config|
|
|
24
|
+
config.left = :dummy
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "configuration should return the current configuration" do
|
|
29
|
+
make_dummy_configuration_change
|
|
30
|
+
Initializer::configuration.should be_an_instance_of(Configuration)
|
|
31
|
+
Initializer::configuration.left.should == :dummy
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "configuration= should set a new configuration" do
|
|
35
|
+
make_dummy_configuration_change
|
|
36
|
+
Initializer::configuration = :dummy_config
|
|
37
|
+
Initializer::configuration.should == :dummy_config
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "reset should clear the configuration" do
|
|
41
|
+
make_dummy_configuration_change
|
|
42
|
+
Initializer::reset
|
|
43
|
+
Initializer::configuration.left.should {}
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
class MyLogHelper
|
|
6
|
+
include LogHelper
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe LogHelper do
|
|
10
|
+
before(:each) do
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should do nothing if the description fields are small enough" do
|
|
14
|
+
MyLogHelper.new.fit_description_columns("bla", "blub").
|
|
15
|
+
should == %w(bla blub)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should cut details to fit into the 'long_description' column" do
|
|
19
|
+
MyLogHelper.new.fit_description_columns(
|
|
20
|
+
"bla",
|
|
21
|
+
"x" * (ReplicationInitializer::LONG_DESCRIPTION_SIZE - 1) + "yz").
|
|
22
|
+
should == ["bla", "x" * (ReplicationInitializer::LONG_DESCRIPTION_SIZE - 1) + "y"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should cut outcome to fit into the 'description' column" do
|
|
26
|
+
MyLogHelper.new.fit_description_columns(
|
|
27
|
+
"x" * (ReplicationInitializer::DESCRIPTION_SIZE - 1) + "yz",
|
|
28
|
+
"blub")[0].
|
|
29
|
+
should == "x" * (ReplicationInitializer::DESCRIPTION_SIZE - 1) + "y"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should carry over a long outcome into the 'long_description' column" do
|
|
33
|
+
MyLogHelper.new.fit_description_columns(
|
|
34
|
+
"x" * (ReplicationInitializer::DESCRIPTION_SIZE - 1) + "yz",
|
|
35
|
+
"blub")[1].
|
|
36
|
+
should == "x" * (ReplicationInitializer::DESCRIPTION_SIZE - 1) + "yz\nblub"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe LoggedChangeLoaders do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initializers should create both logged change loaders" do
|
|
11
|
+
session = Session.new
|
|
12
|
+
loaders = LoggedChangeLoaders.new(session)
|
|
13
|
+
loaders[:left].session.should == session
|
|
14
|
+
loaders[:left].database.should == :left
|
|
15
|
+
loaders[:right].database.should == :right
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "update should execute a forced update of both logged change loaders" do
|
|
19
|
+
session = Session.new
|
|
20
|
+
loaders = LoggedChangeLoaders.new(session)
|
|
21
|
+
loaders[:left].should_receive(:update).with(:forced => true)
|
|
22
|
+
loaders[:right].should_receive(:update).with(:forced => true)
|
|
23
|
+
loaders.update
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe LoggedChangeLoader do
|
|
29
|
+
before(:each) do
|
|
30
|
+
Initializer.configuration = standard_config
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Note:
|
|
34
|
+
# LoggedChangeLoader is a helper for LoggedChange.
|
|
35
|
+
# It is tested through the specs for LoggedChange.
|
|
36
|
+
|
|
37
|
+
it "oldest_change_time should return nil if there are no changes" do
|
|
38
|
+
session = Session.new
|
|
39
|
+
session.left.execute "delete from rr_pending_changes"
|
|
40
|
+
loader = LoggedChangeLoader.new session, :left
|
|
41
|
+
loader.oldest_change_time.should be_nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "oldest_change_time should return the time of the oldest change" do
|
|
45
|
+
session = Session.new
|
|
46
|
+
session.left.begin_db_transaction
|
|
47
|
+
begin
|
|
48
|
+
time = Time.now
|
|
49
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
50
|
+
'change_table' => 'left_table',
|
|
51
|
+
'change_key' => 'id|1',
|
|
52
|
+
'change_type' => 'I',
|
|
53
|
+
'change_time' => time
|
|
54
|
+
}
|
|
55
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
56
|
+
'change_table' => 'left_table',
|
|
57
|
+
'change_key' => 'id|2',
|
|
58
|
+
'change_type' => 'I',
|
|
59
|
+
'change_time' => 100.seconds.from_now
|
|
60
|
+
}
|
|
61
|
+
loader = LoggedChangeLoader.new session, :left
|
|
62
|
+
loader.oldest_change_time.should.to_s == time.to_s
|
|
63
|
+
ensure
|
|
64
|
+
session.left.rollback_db_transaction
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe LoggedChange do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initialize should store session and database" do
|
|
11
|
+
session = Session.new
|
|
12
|
+
loader = LoggedChangeLoader.new session, :left
|
|
13
|
+
change = LoggedChange.new loader
|
|
14
|
+
change.session.should == session
|
|
15
|
+
change.database.should == :left
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "load_specified should load the specified change" do
|
|
19
|
+
session = Session.new
|
|
20
|
+
session.left.begin_db_transaction
|
|
21
|
+
begin
|
|
22
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
23
|
+
'change_table' => 'left_table',
|
|
24
|
+
'change_key' => 'id|1',
|
|
25
|
+
'change_type' => 'I',
|
|
26
|
+
'change_time' => Time.now
|
|
27
|
+
}
|
|
28
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
29
|
+
'change_table' => 'right_table',
|
|
30
|
+
'change_key' => 'id|2',
|
|
31
|
+
'change_new_key' => 'id|2',
|
|
32
|
+
'change_type' => 'U',
|
|
33
|
+
'change_time' => Time.now
|
|
34
|
+
}
|
|
35
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
36
|
+
'change_table' => 'left_table',
|
|
37
|
+
'change_key' => 'id|2',
|
|
38
|
+
'change_type' => 'I',
|
|
39
|
+
'change_time' => Time.now
|
|
40
|
+
}
|
|
41
|
+
loader = LoggedChangeLoader.new session, :left
|
|
42
|
+
change = LoggedChange.new loader
|
|
43
|
+
change.load_specified 'left_table', {'id' => '2'}
|
|
44
|
+
|
|
45
|
+
change.table.should == 'left_table'
|
|
46
|
+
change.type.should == :insert
|
|
47
|
+
change.key.should == {'id' => '2'}
|
|
48
|
+
ensure
|
|
49
|
+
session.left.rollback_db_transaction
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "load_specified should accept a column_name => value hash as key" do
|
|
54
|
+
config = deep_copy(standard_config)
|
|
55
|
+
config.included_table_specs.clear
|
|
56
|
+
config.include_tables "scanner_records", :key => ['id1', 'id2']
|
|
57
|
+
|
|
58
|
+
session = Session.new config
|
|
59
|
+
session.left.begin_db_transaction
|
|
60
|
+
begin
|
|
61
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
62
|
+
'change_table' => 'scanner_records',
|
|
63
|
+
'change_key' => 'id1|1|id2|2',
|
|
64
|
+
'change_type' => 'I',
|
|
65
|
+
'change_time' => Time.now
|
|
66
|
+
}
|
|
67
|
+
loader = LoggedChangeLoader.new session, :left
|
|
68
|
+
change = LoggedChange.new loader
|
|
69
|
+
change.load_specified 'scanner_records', {'id1' => 1, 'id2' => 2}
|
|
70
|
+
|
|
71
|
+
change.table.should == 'scanner_records'
|
|
72
|
+
change.type.should == :insert
|
|
73
|
+
change.key.should == {'id1' => '1', 'id2' => '2'}
|
|
74
|
+
ensure
|
|
75
|
+
session.left.rollback_db_transaction
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "load_specified should delete loaded changes from the database" do
|
|
80
|
+
session = Session.new
|
|
81
|
+
session.left.begin_db_transaction
|
|
82
|
+
begin
|
|
83
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
84
|
+
'change_table' => 'left_table',
|
|
85
|
+
'change_key' => 'id|1',
|
|
86
|
+
'change_type' => 'I',
|
|
87
|
+
'change_time' => Time.now
|
|
88
|
+
}
|
|
89
|
+
loader = LoggedChangeLoader.new session, :left
|
|
90
|
+
change = LoggedChange.new loader
|
|
91
|
+
change.load_specified 'left_table', {'id' => 1}
|
|
92
|
+
|
|
93
|
+
session.left.
|
|
94
|
+
select_one("select * from rr_pending_changes where change_key = 'id|1'").
|
|
95
|
+
should be_nil
|
|
96
|
+
ensure
|
|
97
|
+
session.left.rollback_db_transaction
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "load_specified should set first_change_at and last_changed_at correctly" do
|
|
102
|
+
session = Session.new
|
|
103
|
+
session.left.begin_db_transaction
|
|
104
|
+
begin
|
|
105
|
+
t1 = 5.seconds.ago
|
|
106
|
+
t2 = 5.seconds.from_now
|
|
107
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
108
|
+
'change_table' => 'left_table',
|
|
109
|
+
'change_key' => 'id|1',
|
|
110
|
+
'change_type' => 'I',
|
|
111
|
+
'change_time' => t1
|
|
112
|
+
}
|
|
113
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
114
|
+
'change_table' => 'left_table',
|
|
115
|
+
'change_key' => 'id|1',
|
|
116
|
+
'change_new_key' => 'id|1',
|
|
117
|
+
'change_type' => 'U',
|
|
118
|
+
'change_time' => t2
|
|
119
|
+
}
|
|
120
|
+
loader = LoggedChangeLoader.new session, :left
|
|
121
|
+
change = LoggedChange.new loader
|
|
122
|
+
change.load_specified 'left_table', {'id' => 1}
|
|
123
|
+
|
|
124
|
+
(change.first_changed_at - t1).abs.should < 1
|
|
125
|
+
(change.last_changed_at - t2).abs.should < 1
|
|
126
|
+
ensure
|
|
127
|
+
session.left.rollback_db_transaction
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "load_specified should follow primary key updates correctly" do
|
|
132
|
+
session = Session.new
|
|
133
|
+
session.left.begin_db_transaction
|
|
134
|
+
begin
|
|
135
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
136
|
+
'change_table' => 'left_table',
|
|
137
|
+
'change_key' => 'id|1',
|
|
138
|
+
'change_new_key' => 'id|2',
|
|
139
|
+
'change_type' => 'U',
|
|
140
|
+
'change_time' => Time.now
|
|
141
|
+
}
|
|
142
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
143
|
+
'change_table' => 'left_table',
|
|
144
|
+
'change_key' => 'id|2',
|
|
145
|
+
'change_new_key' => 'id|3',
|
|
146
|
+
'change_type' => 'U',
|
|
147
|
+
'change_time' => Time.now
|
|
148
|
+
}
|
|
149
|
+
loader = LoggedChangeLoader.new session, :left
|
|
150
|
+
change = LoggedChange.new loader
|
|
151
|
+
change.load_specified 'left_table', {'id' => 1}
|
|
152
|
+
|
|
153
|
+
change.type.should == :update
|
|
154
|
+
change.key.should == {'id' => 1}
|
|
155
|
+
change.new_key.should == {'id' => '3'}
|
|
156
|
+
ensure
|
|
157
|
+
session.left.rollback_db_transaction
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "load_specified should recognize if changes cancel each other out" do
|
|
162
|
+
session = Session.new
|
|
163
|
+
session.left.begin_db_transaction
|
|
164
|
+
begin
|
|
165
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
166
|
+
'change_table' => 'left_table',
|
|
167
|
+
'change_key' => 'id|1',
|
|
168
|
+
'change_type' => 'I',
|
|
169
|
+
'change_time' => Time.now
|
|
170
|
+
}
|
|
171
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
172
|
+
'change_table' => 'left_table',
|
|
173
|
+
'change_key' => 'id|1',
|
|
174
|
+
'change_new_key' => 'id|2',
|
|
175
|
+
'change_type' => 'U',
|
|
176
|
+
'change_time' => Time.now
|
|
177
|
+
}
|
|
178
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
179
|
+
'change_table' => 'left_table',
|
|
180
|
+
'change_key' => 'id|2',
|
|
181
|
+
'change_type' => 'D',
|
|
182
|
+
'change_time' => Time.now
|
|
183
|
+
}
|
|
184
|
+
loader = LoggedChangeLoader.new session, :left
|
|
185
|
+
change = LoggedChange.new loader
|
|
186
|
+
change.load_specified 'left_table', {'id' => '1'}
|
|
187
|
+
|
|
188
|
+
change.type.should == :no_change
|
|
189
|
+
ensure
|
|
190
|
+
session.left.rollback_db_transaction
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "load_specified should transist states correctly" do
|
|
195
|
+
session = Session.new
|
|
196
|
+
session.left.begin_db_transaction
|
|
197
|
+
begin
|
|
198
|
+
|
|
199
|
+
# first test case
|
|
200
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
201
|
+
'change_table' => 'left_table',
|
|
202
|
+
'change_key' => 'id|1',
|
|
203
|
+
'change_type' => 'I',
|
|
204
|
+
'change_time' => Time.now
|
|
205
|
+
}
|
|
206
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
207
|
+
'change_table' => 'left_table',
|
|
208
|
+
'change_key' => 'id|1',
|
|
209
|
+
'change_type' => 'D',
|
|
210
|
+
'change_time' => Time.now
|
|
211
|
+
}
|
|
212
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
213
|
+
'change_table' => 'left_table',
|
|
214
|
+
'change_key' => 'id|1',
|
|
215
|
+
'change_type' => 'I',
|
|
216
|
+
'change_time' => Time.now
|
|
217
|
+
}
|
|
218
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
219
|
+
'change_table' => 'left_table',
|
|
220
|
+
'change_key' => 'id|1',
|
|
221
|
+
'change_new_key' => 'id|2',
|
|
222
|
+
'change_type' => 'U',
|
|
223
|
+
'change_time' => Time.now
|
|
224
|
+
}
|
|
225
|
+
loader = LoggedChangeLoader.new session, :left
|
|
226
|
+
change = LoggedChange.new loader
|
|
227
|
+
change.load_specified 'left_table', {'id' => '1'}
|
|
228
|
+
change.type.should == :insert
|
|
229
|
+
change.key.should == {'id' => '2'}
|
|
230
|
+
|
|
231
|
+
# second test case
|
|
232
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
233
|
+
'change_table' => 'left_table',
|
|
234
|
+
'change_key' => 'id|5',
|
|
235
|
+
'change_type' => 'D',
|
|
236
|
+
'change_time' => Time.now
|
|
237
|
+
}
|
|
238
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
239
|
+
'change_table' => 'left_table',
|
|
240
|
+
'change_key' => 'id|5',
|
|
241
|
+
'change_type' => 'I',
|
|
242
|
+
'change_time' => Time.now
|
|
243
|
+
}
|
|
244
|
+
loader.update :forced => true
|
|
245
|
+
change = LoggedChange.new loader
|
|
246
|
+
change.load_specified 'left_table', {'id' => '5'}
|
|
247
|
+
change.type.should == :update
|
|
248
|
+
change.key.should == {'id' => '5'}
|
|
249
|
+
change.new_key.should == {'id' => '5'}
|
|
250
|
+
ensure
|
|
251
|
+
session.left.rollback_db_transaction
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "amend should work if there were no changes" do
|
|
256
|
+
session = Session.new
|
|
257
|
+
session.left.begin_db_transaction
|
|
258
|
+
begin
|
|
259
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
260
|
+
'change_table' => 'scanner_records',
|
|
261
|
+
'change_key' => 'id|1',
|
|
262
|
+
'change_type' => 'I',
|
|
263
|
+
'change_time' => Time.now
|
|
264
|
+
}
|
|
265
|
+
loader = LoggedChangeLoader.new session, :left
|
|
266
|
+
change = LoggedChange.new loader
|
|
267
|
+
change.load_specified 'scanner_records', {'id' => '1'}
|
|
268
|
+
|
|
269
|
+
change.table.should == 'scanner_records'
|
|
270
|
+
change.type.should == :insert
|
|
271
|
+
change.key.should == {'id' => '1'}
|
|
272
|
+
|
|
273
|
+
change.load
|
|
274
|
+
|
|
275
|
+
change.table.should == 'scanner_records'
|
|
276
|
+
change.type.should == :insert
|
|
277
|
+
change.key.should == {'id' => '1'}
|
|
278
|
+
ensure
|
|
279
|
+
session.left.rollback_db_transaction
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it "amend should work if the current type is :no_change" do
|
|
284
|
+
session = Session.new
|
|
285
|
+
session.left.begin_db_transaction
|
|
286
|
+
begin
|
|
287
|
+
loader = LoggedChangeLoader.new session, :left
|
|
288
|
+
change = LoggedChange.new loader
|
|
289
|
+
change.load_specified 'scanner_records', {'id' => '1'}
|
|
290
|
+
|
|
291
|
+
change.table.should == 'scanner_records'
|
|
292
|
+
change.type.should == :no_change
|
|
293
|
+
change.key.should == {'id' => '1'}
|
|
294
|
+
|
|
295
|
+
change.load
|
|
296
|
+
|
|
297
|
+
change.table.should == 'scanner_records'
|
|
298
|
+
change.type.should == :no_change
|
|
299
|
+
change.key.should == {'id' => '1'}
|
|
300
|
+
ensure
|
|
301
|
+
session.left.rollback_db_transaction
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
it "amend should amend the change correctly" do
|
|
306
|
+
session = Session.new
|
|
307
|
+
session.left.begin_db_transaction
|
|
308
|
+
begin
|
|
309
|
+
session.left.insert_record 'left_table', {
|
|
310
|
+
:id => '1',
|
|
311
|
+
:name => 'bla'
|
|
312
|
+
}
|
|
313
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
314
|
+
'change_table' => 'left_table',
|
|
315
|
+
'change_key' => 'id|1',
|
|
316
|
+
'change_new_key' => 'id|1',
|
|
317
|
+
'change_type' => 'U',
|
|
318
|
+
'change_time' => Time.now
|
|
319
|
+
}
|
|
320
|
+
loader = LoggedChangeLoader.new session, :left
|
|
321
|
+
change = LoggedChange.new loader
|
|
322
|
+
change.load_specified 'left_table', {'id' => '1'}
|
|
323
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
324
|
+
'change_table' => 'left_table',
|
|
325
|
+
'change_key' => 'id|1',
|
|
326
|
+
'change_type' => 'D',
|
|
327
|
+
'change_time' => Time.now
|
|
328
|
+
}
|
|
329
|
+
loader.update :forced => true
|
|
330
|
+
change.load
|
|
331
|
+
|
|
332
|
+
change.table.should == 'left_table'
|
|
333
|
+
change.type.should == :delete
|
|
334
|
+
change.key.should == {'id' => '1'}
|
|
335
|
+
ensure
|
|
336
|
+
session.left.rollback_db_transaction
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it "amend should support primary key updates" do
|
|
341
|
+
session = Session.new
|
|
342
|
+
session.left.begin_db_transaction
|
|
343
|
+
begin
|
|
344
|
+
session.left.insert_record 'left_table', {
|
|
345
|
+
:id => '1',
|
|
346
|
+
:name => 'bla'
|
|
347
|
+
}
|
|
348
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
349
|
+
'change_table' => 'left_table',
|
|
350
|
+
'change_key' => 'id|1',
|
|
351
|
+
'change_new_key' => 'id|2',
|
|
352
|
+
'change_type' => 'U',
|
|
353
|
+
'change_time' => Time.now
|
|
354
|
+
}
|
|
355
|
+
loader = LoggedChangeLoader.new session, :left
|
|
356
|
+
change = LoggedChange.new loader
|
|
357
|
+
change.load_specified 'left_table', {'id' => '1'}
|
|
358
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
359
|
+
'change_table' => 'left_table',
|
|
360
|
+
'change_key' => 'id|2',
|
|
361
|
+
'change_new_key' => 'id|3',
|
|
362
|
+
'change_type' => 'U',
|
|
363
|
+
'change_time' => Time.now
|
|
364
|
+
}
|
|
365
|
+
loader.update :forced => true
|
|
366
|
+
change.load
|
|
367
|
+
|
|
368
|
+
change.table.should == 'left_table'
|
|
369
|
+
change.type.should == :update
|
|
370
|
+
change.key.should == {'id' => '1'}
|
|
371
|
+
change.new_key.should == {'id' => '3'}
|
|
372
|
+
ensure
|
|
373
|
+
session.left.rollback_db_transaction
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it "key_from_raw_key should return the correct column_name => value hash for the given key" do
|
|
378
|
+
loader = LoggedChangeLoader.new Session.new, :left
|
|
379
|
+
change = LoggedChange.new loader
|
|
380
|
+
change.key_to_hash("a|1|b|2").should == {
|
|
381
|
+
'a' => '1',
|
|
382
|
+
'b' => '2'
|
|
383
|
+
}
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it "key_from_raw_key should work with multi character key_sep strings" do
|
|
387
|
+
loader = LoggedChangeLoader.new Session.new, :left
|
|
388
|
+
change = LoggedChange.new loader
|
|
389
|
+
change.stub!(:key_sep).and_return('BLA')
|
|
390
|
+
change.key_to_hash("aBLA1BLAbBLA2").should == {
|
|
391
|
+
'a' => '1',
|
|
392
|
+
'b' => '2'
|
|
393
|
+
}
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
it "load_oldest should not load a change if none available" do
|
|
397
|
+
loader = LoggedChangeLoader.new Session.new, :left
|
|
398
|
+
change = LoggedChange.new loader
|
|
399
|
+
change.should_not_receive :load_specified
|
|
400
|
+
change.load_oldest
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
it "load_oldest should load the oldest available change" do
|
|
404
|
+
session = Session.new
|
|
405
|
+
session.left.begin_db_transaction
|
|
406
|
+
begin
|
|
407
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
408
|
+
'change_table' => 'left_table',
|
|
409
|
+
'change_key' => 'id|1',
|
|
410
|
+
'change_type' => 'I',
|
|
411
|
+
'change_time' => Time.now
|
|
412
|
+
}
|
|
413
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
414
|
+
'change_table' => 'left_table',
|
|
415
|
+
'change_key' => 'id|2',
|
|
416
|
+
'change_type' => 'I',
|
|
417
|
+
'change_time' => Time.now
|
|
418
|
+
}
|
|
419
|
+
loader = LoggedChangeLoader.new session, :left
|
|
420
|
+
change = LoggedChange.new loader
|
|
421
|
+
change.load_oldest
|
|
422
|
+
|
|
423
|
+
change.key.should == {'id' => '1'}
|
|
424
|
+
ensure
|
|
425
|
+
session.left.rollback_db_transaction
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
it "load_oldest should skip irrelevant changes" do
|
|
430
|
+
session = Session.new
|
|
431
|
+
session.left.begin_db_transaction
|
|
432
|
+
begin
|
|
433
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
434
|
+
'change_table' => 'left_table',
|
|
435
|
+
'change_key' => 'id|1',
|
|
436
|
+
'change_type' => 'I',
|
|
437
|
+
'change_time' => Time.now
|
|
438
|
+
}
|
|
439
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
440
|
+
'change_table' => 'left_table',
|
|
441
|
+
'change_key' => 'id|1',
|
|
442
|
+
'change_type' => 'D',
|
|
443
|
+
'change_time' => Time.now
|
|
444
|
+
}
|
|
445
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
446
|
+
'change_table' => 'left_table',
|
|
447
|
+
'change_key' => 'id|2',
|
|
448
|
+
'change_type' => 'I',
|
|
449
|
+
'change_time' => Time.now
|
|
450
|
+
}
|
|
451
|
+
loader = LoggedChangeLoader.new session, :left
|
|
452
|
+
change = LoggedChange.new loader
|
|
453
|
+
change.load_oldest
|
|
454
|
+
|
|
455
|
+
change.type.should == :insert
|
|
456
|
+
change.key.should == {'id' => '2'}
|
|
457
|
+
ensure
|
|
458
|
+
session.left.rollback_db_transaction
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
it "to_yaml should blank out session and loader" do
|
|
463
|
+
session = Session.new
|
|
464
|
+
loader = LoggedChangeLoader.new session, :left
|
|
465
|
+
change = LoggedChange.new loader
|
|
466
|
+
yaml = change.to_yaml
|
|
467
|
+
yaml.should_not =~ /session/
|
|
468
|
+
yaml.should_not =~ /loader/
|
|
469
|
+
end
|
|
470
|
+
end
|