rubyrep 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +137 -0
- data/README.txt +37 -0
- data/Rakefile +30 -0
- data/bin/rubyrep +8 -0
- data/config/hoe.rb +72 -0
- data/config/mysql_config.rb +25 -0
- data/config/postgres_config.rb +21 -0
- data/config/proxied_test_config.rb +14 -0
- data/config/redmine_config.rb +17 -0
- data/config/rep_config.rb +20 -0
- data/config/requirements.rb +32 -0
- data/config/test_config.rb +20 -0
- data/lib/rubyrep/base_runner.rb +195 -0
- data/lib/rubyrep/command_runner.rb +144 -0
- data/lib/rubyrep/committers/buffered_committer.rb +140 -0
- data/lib/rubyrep/committers/committers.rb +146 -0
- data/lib/rubyrep/configuration.rb +240 -0
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +133 -0
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +284 -0
- data/lib/rubyrep/connection_extenders/mysql_extender.rb +168 -0
- data/lib/rubyrep/connection_extenders/postgresql_extender.rb +261 -0
- data/lib/rubyrep/database_proxy.rb +52 -0
- data/lib/rubyrep/direct_table_scan.rb +75 -0
- data/lib/rubyrep/generate_runner.rb +105 -0
- data/lib/rubyrep/initializer.rb +39 -0
- data/lib/rubyrep/logged_change.rb +326 -0
- data/lib/rubyrep/proxied_table_scan.rb +171 -0
- data/lib/rubyrep/proxy_block_cursor.rb +145 -0
- data/lib/rubyrep/proxy_connection.rb +318 -0
- data/lib/rubyrep/proxy_cursor.rb +44 -0
- data/lib/rubyrep/proxy_row_cursor.rb +43 -0
- data/lib/rubyrep/proxy_runner.rb +89 -0
- data/lib/rubyrep/replication_difference.rb +91 -0
- data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
- data/lib/rubyrep/replication_extenders/postgresql_replication.rb +204 -0
- data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
- data/lib/rubyrep/replication_helper.rb +104 -0
- data/lib/rubyrep/replication_initializer.rb +307 -0
- data/lib/rubyrep/replication_run.rb +48 -0
- data/lib/rubyrep/replication_runner.rb +138 -0
- data/lib/rubyrep/replicators/replicators.rb +37 -0
- data/lib/rubyrep/replicators/two_way_replicator.rb +334 -0
- data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
- data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
- data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
- data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
- data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
- data/lib/rubyrep/scan_runner.rb +25 -0
- data/lib/rubyrep/session.rb +177 -0
- data/lib/rubyrep/sync_helper.rb +111 -0
- data/lib/rubyrep/sync_runner.rb +31 -0
- data/lib/rubyrep/syncers/syncers.rb +112 -0
- data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
- data/lib/rubyrep/table_scan.rb +54 -0
- data/lib/rubyrep/table_scan_helper.rb +38 -0
- data/lib/rubyrep/table_sorter.rb +70 -0
- data/lib/rubyrep/table_spec_resolver.rb +136 -0
- data/lib/rubyrep/table_sync.rb +68 -0
- data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
- data/lib/rubyrep/type_casting_cursor.rb +31 -0
- data/lib/rubyrep/uninstall_runner.rb +92 -0
- data/lib/rubyrep/version.rb +9 -0
- data/lib/rubyrep.rb +68 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/sims/performance/big_rep_spec.rb +100 -0
- data/sims/performance/big_scan_spec.rb +57 -0
- data/sims/performance/big_sync_spec.rb +141 -0
- data/sims/performance/performance.rake +228 -0
- data/sims/sim_helper.rb +24 -0
- data/spec/base_runner_spec.rb +218 -0
- data/spec/buffered_committer_spec.rb +271 -0
- data/spec/command_runner_spec.rb +145 -0
- data/spec/committers_spec.rb +174 -0
- data/spec/configuration_spec.rb +198 -0
- data/spec/connection_extender_interface_spec.rb +138 -0
- data/spec/connection_extenders_registration_spec.rb +129 -0
- data/spec/database_proxy_spec.rb +48 -0
- data/spec/database_rake_spec.rb +40 -0
- data/spec/db_specific_connection_extenders_spec.rb +34 -0
- data/spec/db_specific_replication_extenders_spec.rb +38 -0
- data/spec/direct_table_scan_spec.rb +61 -0
- data/spec/generate_runner_spec.rb +84 -0
- data/spec/initializer_spec.rb +46 -0
- data/spec/logged_change_spec.rb +480 -0
- data/spec/postgresql_replication_spec.rb +48 -0
- data/spec/postgresql_support_spec.rb +57 -0
- data/spec/progress_bar_spec.rb +77 -0
- data/spec/proxied_table_scan_spec.rb +151 -0
- data/spec/proxy_block_cursor_spec.rb +197 -0
- data/spec/proxy_connection_spec.rb +399 -0
- data/spec/proxy_cursor_spec.rb +56 -0
- data/spec/proxy_row_cursor_spec.rb +66 -0
- data/spec/proxy_runner_spec.rb +70 -0
- data/spec/replication_difference_spec.rb +160 -0
- data/spec/replication_extender_interface_spec.rb +365 -0
- data/spec/replication_extenders_spec.rb +32 -0
- data/spec/replication_helper_spec.rb +121 -0
- data/spec/replication_initializer_spec.rb +477 -0
- data/spec/replication_run_spec.rb +166 -0
- data/spec/replication_runner_spec.rb +213 -0
- data/spec/replicators_spec.rb +31 -0
- data/spec/rubyrep_spec.rb +8 -0
- data/spec/scan_detail_reporter_spec.rb +119 -0
- data/spec/scan_progress_printers_spec.rb +68 -0
- data/spec/scan_report_printers_spec.rb +67 -0
- data/spec/scan_runner_spec.rb +50 -0
- data/spec/scan_summary_reporter_spec.rb +61 -0
- data/spec/session_spec.rb +212 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +295 -0
- data/spec/sync_helper_spec.rb +157 -0
- data/spec/sync_runner_spec.rb +78 -0
- data/spec/syncers_spec.rb +171 -0
- data/spec/table_scan_helper_spec.rb +29 -0
- data/spec/table_scan_spec.rb +49 -0
- data/spec/table_sorter_spec.rb +31 -0
- data/spec/table_spec_resolver_spec.rb +102 -0
- data/spec/table_sync_spec.rb +84 -0
- data/spec/trigger_mode_switcher_spec.rb +83 -0
- data/spec/two_way_replicator_spec.rb +551 -0
- data/spec/two_way_syncer_spec.rb +256 -0
- data/spec/type_casting_cursor_spec.rb +50 -0
- data/spec/uninstall_runner_spec.rb +86 -0
- data/tasks/database.rake +439 -0
- data/tasks/deployment.rake +29 -0
- data/tasks/environment.rake +9 -0
- data/tasks/java.rake +37 -0
- data/tasks/redmine_test.rake +47 -0
- data/tasks/rspec.rake +68 -0
- data/tasks/rubyrep.tailor +18 -0
- data/tasks/stats.rake +19 -0
- data/tasks/task_helper.rb +20 -0
- data.tar.gz.sig +0 -0
- metadata +243 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ReplicationDifference do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initialize should store the session" do
|
|
11
|
+
session = Session.new
|
|
12
|
+
diff = ReplicationDifference.new session
|
|
13
|
+
diff.session.should == session
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "loaded? should return true if a difference was loaded" do
|
|
17
|
+
diff = ReplicationDifference.new Session.new
|
|
18
|
+
diff.should_not be_loaded
|
|
19
|
+
diff.loaded = true
|
|
20
|
+
diff.should be_loaded
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "load should leave the instance unloaded if no changes are available" do
|
|
24
|
+
diff = ReplicationDifference.new Session.new
|
|
25
|
+
diff.load
|
|
26
|
+
diff.should_not be_loaded
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "load should load left differences successfully" do
|
|
30
|
+
session = Session.new
|
|
31
|
+
session.left.begin_db_transaction
|
|
32
|
+
begin
|
|
33
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
34
|
+
'change_table' => 'scanner_records',
|
|
35
|
+
'change_key' => 'id|1',
|
|
36
|
+
'change_type' => 'I',
|
|
37
|
+
'change_time' => Time.now
|
|
38
|
+
}
|
|
39
|
+
diff = ReplicationDifference.new session
|
|
40
|
+
diff.load
|
|
41
|
+
|
|
42
|
+
diff.should be_loaded
|
|
43
|
+
diff.type.should == :left
|
|
44
|
+
diff.changes[:left].key.should == {'id' => '1'}
|
|
45
|
+
ensure
|
|
46
|
+
session.left.rollback_db_transaction
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "load should load right differences successfully" do
|
|
51
|
+
session = Session.new
|
|
52
|
+
session.right.begin_db_transaction
|
|
53
|
+
begin
|
|
54
|
+
session.right.insert_record 'rr_pending_changes', {
|
|
55
|
+
'change_table' => 'scanner_records',
|
|
56
|
+
'change_key' => 'id|1',
|
|
57
|
+
'change_type' => 'D',
|
|
58
|
+
'change_time' => Time.now
|
|
59
|
+
}
|
|
60
|
+
diff = ReplicationDifference.new session
|
|
61
|
+
diff.load
|
|
62
|
+
|
|
63
|
+
diff.should be_loaded
|
|
64
|
+
diff.type.should == :right
|
|
65
|
+
diff.changes[:right].key.should == {'id' => '1'}
|
|
66
|
+
ensure
|
|
67
|
+
session.right.rollback_db_transaction
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "load should load conflict differences successfully" do
|
|
72
|
+
config = deep_copy(standard_config)
|
|
73
|
+
config.included_table_specs.clear
|
|
74
|
+
config.include_tables "table_with_manual_key, extender_without_key"
|
|
75
|
+
|
|
76
|
+
session = Session.new config
|
|
77
|
+
session.left.begin_db_transaction
|
|
78
|
+
session.right.begin_db_transaction
|
|
79
|
+
begin
|
|
80
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
81
|
+
'change_table' => 'dummy_table',
|
|
82
|
+
'change_key' => 'id|2',
|
|
83
|
+
'change_type' => 'I',
|
|
84
|
+
'change_time' => Time.now
|
|
85
|
+
}
|
|
86
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
87
|
+
'change_table' => 'table_with_manual_key',
|
|
88
|
+
'change_key' => 'id|1',
|
|
89
|
+
'change_new_key' => 'id|1',
|
|
90
|
+
'change_type' => 'U',
|
|
91
|
+
'change_time' => 5.seconds.from_now
|
|
92
|
+
}
|
|
93
|
+
session.right.insert_record 'rr_pending_changes', {
|
|
94
|
+
'change_table' => 'extender_without_key',
|
|
95
|
+
'change_key' => 'id|1',
|
|
96
|
+
'change_type' => 'D',
|
|
97
|
+
'change_time' => 5.seconds.ago
|
|
98
|
+
}
|
|
99
|
+
diff = ReplicationDifference.new session
|
|
100
|
+
diff.load
|
|
101
|
+
|
|
102
|
+
diff.should be_loaded
|
|
103
|
+
diff.type.should == :conflict
|
|
104
|
+
diff.changes[:left].type.should == :update
|
|
105
|
+
diff.changes[:left].table.should == 'table_with_manual_key'
|
|
106
|
+
diff.changes[:left].key.should == {'id' => '1'}
|
|
107
|
+
diff.changes[:right].type.should == :delete
|
|
108
|
+
diff.changes[:right].table.should == 'extender_without_key'
|
|
109
|
+
diff.changes[:right].key.should == {'id' => '1'}
|
|
110
|
+
ensure
|
|
111
|
+
session.left.rollback_db_transaction
|
|
112
|
+
session.right.rollback_db_transaction
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "amend should amend the replication difference with new found changes" do
|
|
117
|
+
session = Session.new
|
|
118
|
+
session.left.begin_db_transaction
|
|
119
|
+
session.right.begin_db_transaction
|
|
120
|
+
begin
|
|
121
|
+
session.right.insert_record 'rr_pending_changes', {
|
|
122
|
+
'change_table' => 'scanner_records',
|
|
123
|
+
'change_key' => 'id|1',
|
|
124
|
+
'change_type' => 'I',
|
|
125
|
+
'change_time' => Time.now
|
|
126
|
+
}
|
|
127
|
+
diff = ReplicationDifference.new session
|
|
128
|
+
diff.load
|
|
129
|
+
|
|
130
|
+
diff.should be_loaded
|
|
131
|
+
diff.type.should == :right
|
|
132
|
+
diff.changes[:right].key.should == {'id' => '1'}
|
|
133
|
+
|
|
134
|
+
# if there are no changes, the diff should still be the same
|
|
135
|
+
diff.amend
|
|
136
|
+
diff.type.should == :right
|
|
137
|
+
diff.changes[:right].key.should == {'id' => '1'}
|
|
138
|
+
|
|
139
|
+
# should recognize new changes
|
|
140
|
+
session.left.insert_record 'rr_pending_changes', {
|
|
141
|
+
'change_table' => 'scanner_records',
|
|
142
|
+
'change_key' => 'id|1',
|
|
143
|
+
'change_type' => 'D',
|
|
144
|
+
'change_time' => Time.now
|
|
145
|
+
}
|
|
146
|
+
diff.amend
|
|
147
|
+
diff.type.should == :conflict
|
|
148
|
+
diff.changes[:left].key.should == {'id' => '1'}
|
|
149
|
+
diff.changes[:right].key.should == {'id' => '1'}
|
|
150
|
+
ensure
|
|
151
|
+
session.right.rollback_db_transaction
|
|
152
|
+
session.left.rollback_db_transaction
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "to_yaml should blank out session" do
|
|
157
|
+
diff = ReplicationDifference.new :dummy_session
|
|
158
|
+
diff.to_yaml.should_not =~ /session/
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
|
|
4
|
+
include RR
|
|
5
|
+
|
|
6
|
+
# All ReplicationExtenders need to pass this spec
|
|
7
|
+
describe "ReplicationExtender", :shared => true do
|
|
8
|
+
before(:each) do
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "create_replication_trigger created triggers should log data changes" do
|
|
12
|
+
session = nil
|
|
13
|
+
begin
|
|
14
|
+
session = Session.new
|
|
15
|
+
session.left.begin_db_transaction
|
|
16
|
+
params = {
|
|
17
|
+
:trigger_name => 'rr_trigger_test',
|
|
18
|
+
:table => 'trigger_test',
|
|
19
|
+
:keys => ['first_id', 'second_id'],
|
|
20
|
+
:log_table => 'rr_pending_changes',
|
|
21
|
+
:key_sep => '|',
|
|
22
|
+
:exclude_rr_activity => false,
|
|
23
|
+
}
|
|
24
|
+
session.left.create_replication_trigger params
|
|
25
|
+
|
|
26
|
+
change_start = Time.now
|
|
27
|
+
|
|
28
|
+
session.left.insert_record 'trigger_test', {
|
|
29
|
+
'first_id' => 1,
|
|
30
|
+
'second_id' => 2,
|
|
31
|
+
'name' => 'bla'
|
|
32
|
+
}
|
|
33
|
+
session.left.execute "update trigger_test set second_id = 9 where first_id = 1 and second_id = 2"
|
|
34
|
+
session.left.delete_record 'trigger_test', {
|
|
35
|
+
'first_id' => 1,
|
|
36
|
+
'second_id' => 9,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
rows = session.left.connection.select_all("select * from rr_pending_changes order by id")
|
|
40
|
+
|
|
41
|
+
# Verify that the timestamps are created correctly
|
|
42
|
+
rows.each do |row|
|
|
43
|
+
Time.parse(row['change_time']).to_i >= change_start.to_i
|
|
44
|
+
Time.parse(row['change_time']).to_i <= Time.now.to_i
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
rows.each {|row| row.delete 'id'; row.delete 'change_time'}
|
|
48
|
+
rows.should == [
|
|
49
|
+
{'change_table' => 'trigger_test', 'change_key' => 'first_id|1|second_id|2', 'change_new_key' => nil, 'change_type' => 'I'},
|
|
50
|
+
{'change_table' => 'trigger_test', 'change_key' => 'first_id|1|second_id|2', 'change_new_key' => 'first_id|1|second_id|9', 'change_type' => 'U'},
|
|
51
|
+
{'change_table' => 'trigger_test', 'change_key' => 'first_id|1|second_id|9', 'change_new_key' => nil, 'change_type' => 'D'},
|
|
52
|
+
]
|
|
53
|
+
ensure
|
|
54
|
+
session.left.execute 'delete from trigger_test' if session
|
|
55
|
+
session.left.execute 'delete from rr_pending_changes' if session
|
|
56
|
+
session.left.rollback_db_transaction if session
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "created triggers should not log rubyrep initiated changes if :exclude_rubyrep_activity is true" do
|
|
61
|
+
session = nil
|
|
62
|
+
begin
|
|
63
|
+
session = Session.new
|
|
64
|
+
session.left.begin_db_transaction
|
|
65
|
+
params = {
|
|
66
|
+
:trigger_name => 'rr_trigger_test',
|
|
67
|
+
:table => 'trigger_test',
|
|
68
|
+
:keys => ['first_id', 'second_id'],
|
|
69
|
+
:log_table => 'rr_pending_changes',
|
|
70
|
+
:key_sep => '|',
|
|
71
|
+
:exclude_rr_activity => true,
|
|
72
|
+
:activity_table => "rr_running_flags",
|
|
73
|
+
}
|
|
74
|
+
session.left.create_replication_trigger params
|
|
75
|
+
|
|
76
|
+
session.left.insert_record 'rr_running_flags', {
|
|
77
|
+
'active' => 1
|
|
78
|
+
}
|
|
79
|
+
session.left.insert_record 'trigger_test', {
|
|
80
|
+
'first_id' => 1,
|
|
81
|
+
'second_id' => 2,
|
|
82
|
+
'name' => 'bla'
|
|
83
|
+
}
|
|
84
|
+
session.left.connection.execute('delete from rr_running_flags')
|
|
85
|
+
session.left.insert_record 'trigger_test', {
|
|
86
|
+
'first_id' => 1,
|
|
87
|
+
'second_id' => 3,
|
|
88
|
+
'name' => 'bla'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
rows = session.left.connection.select_all("select * from rr_pending_changes order by id")
|
|
92
|
+
rows.each {|row| row.delete 'id'; row.delete 'change_time'}
|
|
93
|
+
rows.should == [{
|
|
94
|
+
'change_table' => 'trigger_test',
|
|
95
|
+
'change_key' => 'first_id|1|second_id|3',
|
|
96
|
+
'change_new_key' => nil,
|
|
97
|
+
'change_type' => 'I'
|
|
98
|
+
}]
|
|
99
|
+
ensure
|
|
100
|
+
session.left.execute 'delete from trigger_test' if session
|
|
101
|
+
session.left.execute 'delete from rr_pending_changes' if session
|
|
102
|
+
session.left.rollback_db_transaction if session
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "created triggers should work with tables having non-combined primary keys" do
|
|
107
|
+
session = nil
|
|
108
|
+
begin
|
|
109
|
+
session = Session.new
|
|
110
|
+
session.left.begin_db_transaction
|
|
111
|
+
params = {
|
|
112
|
+
:trigger_name => 'rr_extender_no_record',
|
|
113
|
+
:table => 'extender_no_record',
|
|
114
|
+
:keys => ['id'],
|
|
115
|
+
:log_table => 'rr_pending_changes',
|
|
116
|
+
:key_sep => '|',
|
|
117
|
+
}
|
|
118
|
+
session.left.create_replication_trigger params
|
|
119
|
+
session.left.insert_record 'extender_no_record', {
|
|
120
|
+
'id' => 9,
|
|
121
|
+
'name' => 'bla'
|
|
122
|
+
}
|
|
123
|
+
rows = session.left.connection.select_all("select * from rr_pending_changes order by id")
|
|
124
|
+
rows.each {|row| row.delete 'id'; row.delete 'change_time'}
|
|
125
|
+
rows.should == [{
|
|
126
|
+
'change_table' => 'extender_no_record',
|
|
127
|
+
'change_key' => 'id|9',
|
|
128
|
+
'change_new_key' => nil,
|
|
129
|
+
'change_type' => 'I'
|
|
130
|
+
}]
|
|
131
|
+
ensure
|
|
132
|
+
if session
|
|
133
|
+
session.left.execute 'delete from extender_no_record'
|
|
134
|
+
session.left.execute 'delete from rr_pending_changes'
|
|
135
|
+
session.left.drop_replication_trigger('rr_extender_no_record', 'extender_no_record')
|
|
136
|
+
session.left.rollback_db_transaction
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "created triggers should work with primary keys holding multi-byte text values" do
|
|
142
|
+
session = nil
|
|
143
|
+
begin
|
|
144
|
+
session = Session.new
|
|
145
|
+
session.left.begin_db_transaction
|
|
146
|
+
params = {
|
|
147
|
+
:trigger_name => 'rr_scanner_text_key',
|
|
148
|
+
:table => 'scanner_text_key',
|
|
149
|
+
:keys => ['text_id'],
|
|
150
|
+
:log_table => 'rr_pending_changes',
|
|
151
|
+
:key_sep => '|',
|
|
152
|
+
}
|
|
153
|
+
session.left.create_replication_trigger params
|
|
154
|
+
session.left.insert_record 'scanner_text_key', {
|
|
155
|
+
'text_id' => 'よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor.',
|
|
156
|
+
'name' => 'bla'
|
|
157
|
+
}
|
|
158
|
+
rows = session.left.connection.select_all("select * from rr_pending_changes order by id")
|
|
159
|
+
rows.each {|row| row.delete 'id'; row.delete 'change_time'}
|
|
160
|
+
rows.should == [{
|
|
161
|
+
'change_table' => 'scanner_text_key',
|
|
162
|
+
'change_key' => 'text_id|よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor.',
|
|
163
|
+
'change_new_key' => nil,
|
|
164
|
+
'change_type' => 'I'
|
|
165
|
+
}]
|
|
166
|
+
found_key = rows[0]['change_key'].sub(/^text_id\|/, '')
|
|
167
|
+
session.left.
|
|
168
|
+
select_one("select * from scanner_text_key where text_id = '#{found_key}'").
|
|
169
|
+
should_not be_nil
|
|
170
|
+
ensure
|
|
171
|
+
if session
|
|
172
|
+
session.left.execute "delete from scanner_text_key where text_id = 'よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor.'"
|
|
173
|
+
session.left.execute 'delete from rr_pending_changes'
|
|
174
|
+
session.left.drop_replication_trigger('rr_scanner_text_key', 'scanner_text_key')
|
|
175
|
+
session.left.rollback_db_transaction
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "replication_trigger_exists? and drop_replication_trigger should work correctly" do
|
|
181
|
+
session = nil
|
|
182
|
+
begin
|
|
183
|
+
session = Session.new
|
|
184
|
+
if session.left.replication_trigger_exists?('rr_trigger_test', 'trigger_test')
|
|
185
|
+
session.left.drop_replication_trigger('rr_trigger_test', 'trigger_test')
|
|
186
|
+
end
|
|
187
|
+
session.left.begin_db_transaction
|
|
188
|
+
params = {
|
|
189
|
+
:trigger_name => 'rr_trigger_test',
|
|
190
|
+
:table => 'trigger_test',
|
|
191
|
+
:keys => ['first_id'],
|
|
192
|
+
:log_table => 'rr_pending_changes',
|
|
193
|
+
:key_sep => '|',
|
|
194
|
+
}
|
|
195
|
+
session.left.create_replication_trigger params
|
|
196
|
+
|
|
197
|
+
session.left.replication_trigger_exists?('rr_trigger_test', 'trigger_test').
|
|
198
|
+
should be_true
|
|
199
|
+
session.left.drop_replication_trigger('rr_trigger_test', 'trigger_test')
|
|
200
|
+
session.left.replication_trigger_exists?('rr_trigger_test', 'trigger_test').
|
|
201
|
+
should be_false
|
|
202
|
+
ensure
|
|
203
|
+
session.left.rollback_db_transaction if session
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it "sequence_values should return an empty hash if table has no sequences" do
|
|
208
|
+
session = Session.new
|
|
209
|
+
session.left.sequence_values('rr', 'scanner_text_key').
|
|
210
|
+
should == {}
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it "sequence_values should return the correct sequence settings" do
|
|
214
|
+
session = nil
|
|
215
|
+
begin
|
|
216
|
+
session = Session.new
|
|
217
|
+
session.left.begin_db_transaction
|
|
218
|
+
session.left.execute 'delete from sequence_test'
|
|
219
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
220
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
221
|
+
session.left.update_sequences \
|
|
222
|
+
'rr', 'sequence_test', 5, 2,
|
|
223
|
+
left_sequence_values, right_sequence_values, 5
|
|
224
|
+
sequence_value = session.left.sequence_values('rr', 'sequence_test').values[0]
|
|
225
|
+
sequence_value[:increment].should == 5
|
|
226
|
+
(sequence_value[:value] % 5).should == 2
|
|
227
|
+
ensure
|
|
228
|
+
session.left.clear_sequence_setup 'rr', 'sequence_test' if session
|
|
229
|
+
session.left.execute "delete from sequence_test" if session
|
|
230
|
+
session.left.rollback_db_transaction if session
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "update_sequences should ensure that a table's auto generated ID values have the correct increment and offset" do
|
|
235
|
+
session = nil
|
|
236
|
+
begin
|
|
237
|
+
session = Session.new
|
|
238
|
+
session.left.begin_db_transaction
|
|
239
|
+
|
|
240
|
+
# Note:
|
|
241
|
+
# Calling ensure_sequence_setup twice with different values to ensure that
|
|
242
|
+
# it is actually does something.
|
|
243
|
+
|
|
244
|
+
session.left.execute 'delete from sequence_test'
|
|
245
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
246
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
247
|
+
session.left.update_sequences \
|
|
248
|
+
'rr', 'sequence_test', 1, 0,
|
|
249
|
+
left_sequence_values, right_sequence_values, 5
|
|
250
|
+
id1, id2 = get_example_sequence_values(session)
|
|
251
|
+
(id2 - id1).should == 1
|
|
252
|
+
|
|
253
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
254
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
255
|
+
session.left.update_sequences \
|
|
256
|
+
'rr', 'sequence_test', 5, 2,
|
|
257
|
+
left_sequence_values, right_sequence_values, 5
|
|
258
|
+
id1, id2 = get_example_sequence_values(session)
|
|
259
|
+
(id2 - id1).should == 5
|
|
260
|
+
(id1 % 5).should == 2
|
|
261
|
+
ensure
|
|
262
|
+
session.left.clear_sequence_setup 'rr', 'sequence_test' if session
|
|
263
|
+
session.left.execute "delete from sequence_test" if session
|
|
264
|
+
session.left.rollback_db_transaction if session
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it "update_sequences shoud set the sequence up correctly if the table is not empty" do
|
|
269
|
+
session = nil
|
|
270
|
+
begin
|
|
271
|
+
session = Session.new
|
|
272
|
+
session.left.begin_db_transaction
|
|
273
|
+
session.left.execute 'delete from sequence_test'
|
|
274
|
+
session.left.insert_record 'sequence_test', { 'name' => 'whatever' }
|
|
275
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
276
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
277
|
+
session.left.update_sequences \
|
|
278
|
+
'rr', 'sequence_test', 2, 0,
|
|
279
|
+
left_sequence_values, right_sequence_values, 5
|
|
280
|
+
id1, id2 = get_example_sequence_values(session)
|
|
281
|
+
(id2 - id1).should == 2
|
|
282
|
+
ensure
|
|
283
|
+
session.left.clear_sequence_setup 'rr', 'sequence_test' if session
|
|
284
|
+
session.left.execute "delete from sequence_test" if session
|
|
285
|
+
session.left.rollback_db_transaction if session
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it "update_sequences shoud set the sequence up correctly if the other table is already set up correctly" do
|
|
290
|
+
session = nil
|
|
291
|
+
begin
|
|
292
|
+
session = Session.new
|
|
293
|
+
session.left.begin_db_transaction
|
|
294
|
+
session.right.begin_db_transaction
|
|
295
|
+
session.left.execute 'delete from sequence_test'
|
|
296
|
+
session.left.insert_record 'sequence_test', { 'name' => 'whatever' }
|
|
297
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
298
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
299
|
+
|
|
300
|
+
# setup right table sequence
|
|
301
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
302
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
303
|
+
session.right.update_sequences \
|
|
304
|
+
'rr', 'sequence_test', 2, 1,
|
|
305
|
+
left_sequence_values, right_sequence_values, 5
|
|
306
|
+
|
|
307
|
+
# now setup left table sequence and verify result
|
|
308
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
309
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
310
|
+
session.left.update_sequences \
|
|
311
|
+
'rr', 'sequence_test', 2, 0,
|
|
312
|
+
left_sequence_values, right_sequence_values, 5
|
|
313
|
+
id1, id2 = get_example_sequence_values(session)
|
|
314
|
+
(id2 - id1).should == 2
|
|
315
|
+
ensure
|
|
316
|
+
session.left.clear_sequence_setup 'rr', 'sequence_test' if session
|
|
317
|
+
session.right.clear_sequence_setup 'rr', 'sequence_test' if session
|
|
318
|
+
session.left.execute "delete from sequence_test" if session
|
|
319
|
+
session.left.rollback_db_transaction if session
|
|
320
|
+
session.right.rollback_db_transaction if session
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
it "clear_sequence_setup should remove custom sequence settings" do
|
|
325
|
+
session = nil
|
|
326
|
+
begin
|
|
327
|
+
session = Session.new
|
|
328
|
+
session.left.begin_db_transaction
|
|
329
|
+
left_sequence_values = session.left.sequence_values 'rr', 'sequence_test'
|
|
330
|
+
right_sequence_values = session.right.sequence_values 'rr', 'sequence_test'
|
|
331
|
+
session.left.update_sequences \
|
|
332
|
+
'rr', 'sequence_test', 2, 0,
|
|
333
|
+
left_sequence_values, right_sequence_values, 5
|
|
334
|
+
session.left.clear_sequence_setup 'rr', 'sequence_test'
|
|
335
|
+
id1, id2 = get_example_sequence_values(session)
|
|
336
|
+
(id2 - id1).should == 1
|
|
337
|
+
ensure
|
|
338
|
+
session.left.clear_sequence_setup 'rr', 'sequence_test' if session
|
|
339
|
+
session.left.execute "delete from sequence_test" if session
|
|
340
|
+
session.left.rollback_db_transaction if session
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it "add_big_primary_key should add a 8 byte, auto incrementing primary key" do
|
|
345
|
+
session = nil
|
|
346
|
+
begin
|
|
347
|
+
session = Session.new
|
|
348
|
+
session.left.drop_table 'big_key_test' if session.left.tables.include? 'big_key_test'
|
|
349
|
+
session.left.create_table 'big_key_test'.to_sym, :id => false do |t|
|
|
350
|
+
t.column :name, :string
|
|
351
|
+
end
|
|
352
|
+
session.left.add_big_primary_key 'big_key_test', 'id'
|
|
353
|
+
|
|
354
|
+
# should auto generate the primary key if not manually specified
|
|
355
|
+
session.left.insert_record 'big_key_test', {'name' => 'bla'}
|
|
356
|
+
session.left.select_one("select id from big_key_test where name = 'bla'")['id'].
|
|
357
|
+
to_i.should > 0
|
|
358
|
+
|
|
359
|
+
# should allow 8 byte values
|
|
360
|
+
session.left.insert_record 'big_key_test', {'id' => 1e18.to_i, 'name' => 'blub'}
|
|
361
|
+
session.left.select_one("select id from big_key_test where name = 'blub'")['id'].
|
|
362
|
+
to_i.should == 1e18.to_i
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ReplicationExtenders do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
@@old_cache_status = ConnectionExtenders.use_db_connection_cache(false)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after(:each) do
|
|
12
|
+
ConnectionExtenders.use_db_connection_cache(@@old_cache_status)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "extenders should return list of registered connection extenders" do
|
|
16
|
+
ReplicationExtenders.extenders.include?(:postgresql).should be_true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "register should register a new connection extender" do
|
|
20
|
+
ReplicationExtenders.register(:bla => :blub)
|
|
21
|
+
|
|
22
|
+
ReplicationExtenders.extenders.include?(:bla).should be_true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "register should replace already existing connection extenders" do
|
|
26
|
+
ReplicationExtenders.register(:bla => :blub)
|
|
27
|
+
ReplicationExtenders.register(:bla => :blub2)
|
|
28
|
+
|
|
29
|
+
ReplicationExtenders.extenders[:bla].should == :blub2
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ReplicationHelper do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initialize should initialize the correct committer" do
|
|
11
|
+
session = Session.new
|
|
12
|
+
rep_run = ReplicationRun.new(session)
|
|
13
|
+
helper = ReplicationHelper.new(rep_run)
|
|
14
|
+
c = helper.instance_eval {@committer}
|
|
15
|
+
c.should be_an_instance_of(Committers::DefaultCommitter)
|
|
16
|
+
c.session.should == helper.session
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "session should return the session" do
|
|
20
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
21
|
+
helper = ReplicationHelper.new(rep_run)
|
|
22
|
+
helper.session.should == rep_run.session
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "replication_run should return the current ReplicationRun instance" do
|
|
26
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
27
|
+
helper = ReplicationHelper.new(rep_run)
|
|
28
|
+
helper.replication_run.should == rep_run
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "options should return the correct options" do
|
|
32
|
+
session = Session.new
|
|
33
|
+
rep_run = ReplicationRun.new(session)
|
|
34
|
+
helper = ReplicationHelper.new(rep_run)
|
|
35
|
+
helper.options.should == session.configuration.options
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "insert_record should insert the given record" do
|
|
39
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
40
|
+
helper = ReplicationHelper.new(rep_run)
|
|
41
|
+
c = helper.instance_eval {committer}
|
|
42
|
+
c.should_receive(:insert_record).with(:right, 'scanner_records', :dummy_record)
|
|
43
|
+
helper.insert_record :right, 'scanner_records', :dummy_record
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "update_record should update the given record" do
|
|
47
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
48
|
+
helper = ReplicationHelper.new(rep_run)
|
|
49
|
+
c = helper.instance_eval {committer}
|
|
50
|
+
c.should_receive(:update_record).with(:right, 'scanner_records', :dummy_record, nil)
|
|
51
|
+
helper.update_record :right, 'scanner_records', :dummy_record
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "update_record should update the given record with the provided old key" do
|
|
55
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
56
|
+
helper = ReplicationHelper.new(rep_run)
|
|
57
|
+
c = helper.instance_eval {committer}
|
|
58
|
+
c.should_receive(:update_record).with(:right, 'scanner_records', :dummy_record, :old_key)
|
|
59
|
+
helper.update_record :right, 'scanner_records', :dummy_record, :old_key
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "delete_record should delete the given record" do
|
|
63
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
64
|
+
helper = ReplicationHelper.new(rep_run)
|
|
65
|
+
c = helper.instance_eval {committer}
|
|
66
|
+
c.should_receive(:delete_record).with(:right, 'scanner_records', :dummy_record)
|
|
67
|
+
helper.delete_record :right, 'scanner_records', :dummy_record
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "load_record should load the specified record (values converted to original data types)" do
|
|
71
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
72
|
+
helper = ReplicationHelper.new(rep_run)
|
|
73
|
+
helper.load_record(:right, 'scanner_records', 'id' => '2').should == {
|
|
74
|
+
'id' => 2, # Note: it's a number, not a string...
|
|
75
|
+
'name' => 'Bob - right database version'
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "log_replication_outcome should log the replication outcome correctly" do
|
|
80
|
+
session = Session.new
|
|
81
|
+
session.left.begin_db_transaction
|
|
82
|
+
begin
|
|
83
|
+
rep_run = ReplicationRun.new(session)
|
|
84
|
+
helper = ReplicationHelper.new(rep_run)
|
|
85
|
+
left_change = LoggedChange.new session, :left
|
|
86
|
+
right_change = LoggedChange.new session, :right
|
|
87
|
+
diff = ReplicationDifference.new session
|
|
88
|
+
diff.changes.replace :left => left_change, :right => right_change
|
|
89
|
+
diff.type = :conflict
|
|
90
|
+
|
|
91
|
+
left_change.type, right_change.type = :update, :delete
|
|
92
|
+
left_change.table = right_change.table = 'extender_combined_key'
|
|
93
|
+
left_change.key = right_change.key = {'first_id' => 1, 'second_id' => 2}
|
|
94
|
+
|
|
95
|
+
helper.log_replication_outcome diff, 'ignore', 'ignored'
|
|
96
|
+
|
|
97
|
+
row = session.left.select_one("select * from rr_logged_events order by id desc")
|
|
98
|
+
row['activity'].should == 'replication'
|
|
99
|
+
row['change_table'].should == 'extender_combined_key'
|
|
100
|
+
row['diff_type'].should == 'conflict'
|
|
101
|
+
row['change_key'].should == '"first_id"=>"1", "second_id"=>"2"'
|
|
102
|
+
row['left_change_type'].should == 'update'
|
|
103
|
+
row['right_change_type'].should == 'delete'
|
|
104
|
+
row['description'].should == 'ignore'
|
|
105
|
+
row['long_description'].should == 'ignored'
|
|
106
|
+
Time.parse(row['event_time']).should >= 10.seconds.ago
|
|
107
|
+
row['diff_dump'].should == diff.to_yaml
|
|
108
|
+
ensure
|
|
109
|
+
session.left.rollback_db_transaction if session
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "finalize should be delegated to the committer" do
|
|
114
|
+
rep_run = ReplicationRun.new(Session.new)
|
|
115
|
+
helper = ReplicationHelper.new(rep_run)
|
|
116
|
+
|
|
117
|
+
c = helper.instance_eval {@committer}
|
|
118
|
+
c.should_receive(:finalize).with(false)
|
|
119
|
+
helper.finalize(false)
|
|
120
|
+
end
|
|
121
|
+
end
|