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,151 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ProxiedTableScan do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = deep_copy(proxied_config)
|
|
8
|
+
|
|
9
|
+
# Small block size necessary to exercize all code paths in ProxiedTableScan
|
|
10
|
+
# even when only using tables with very small number of records.
|
|
11
|
+
Initializer.configuration.options[:proxy_block_size] = 2
|
|
12
|
+
|
|
13
|
+
ensure_proxy
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "initialize should raise exception if session is not proxied" do
|
|
17
|
+
session = Session.new standard_config
|
|
18
|
+
lambda { ProxiedTableScan.new session, 'dummy_table' } \
|
|
19
|
+
.should raise_error(RuntimeError, /only works with proxied sessions/)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "initialize should cache the primary keys" do
|
|
23
|
+
session = Session.new
|
|
24
|
+
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
25
|
+
scan.primary_key_names.should == ['id']
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "initialize should raise exception if table doesn't have primary keys" do
|
|
29
|
+
session = Session.new
|
|
30
|
+
lambda {ProxiedTableScan.new session, 'extender_without_key'} \
|
|
31
|
+
.should raise_error(RuntimeError, /.*extender_without_key.*primary key/)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "block_size should return the :proxy_block_size value of the session options" do
|
|
35
|
+
ProxiedTableScan.new(Session.new, 'scanner_records').block_size \
|
|
36
|
+
.should == 2
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "block_size should return the matching table specific option if available" do
|
|
40
|
+
config = Initializer.configuration
|
|
41
|
+
old_table_specific_options = config.tables_with_options
|
|
42
|
+
begin
|
|
43
|
+
config.options = {:proxy_block_size => 2}
|
|
44
|
+
config.include_tables 'scanner_records', {:proxy_block_size => 3}
|
|
45
|
+
ProxiedTableScan.new(Session.new(config), 'scanner_records').block_size \
|
|
46
|
+
.should == 3
|
|
47
|
+
ensure
|
|
48
|
+
config.instance_eval {@tables_with_options = old_table_specific_options}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Creates, prepares and returns a +ProxyBlockCursor+ for the given database
|
|
53
|
+
# +connection+ and +table+.
|
|
54
|
+
# Sets the ProxyBlockCursor#max_row_cache_size as per method parameter.
|
|
55
|
+
def get_block_cursor(connection, table, max_row_cache_size = 1000000)
|
|
56
|
+
cursor = ProxyBlockCursor.new connection, table
|
|
57
|
+
cursor.max_row_cache_size = max_row_cache_size
|
|
58
|
+
cursor.prepare_fetch
|
|
59
|
+
cursor.checksum :proxy_block_size => 1000
|
|
60
|
+
cursor
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "compare_blocks should compare all the records in the range" do
|
|
64
|
+
session = Session.new
|
|
65
|
+
|
|
66
|
+
left_cursor = get_block_cursor session.left, 'scanner_records'
|
|
67
|
+
right_cursor = get_block_cursor session.right, 'scanner_records'
|
|
68
|
+
|
|
69
|
+
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
70
|
+
diff = []
|
|
71
|
+
scan.compare_blocks(left_cursor, right_cursor) do |type, row|
|
|
72
|
+
diff.push [type, row]
|
|
73
|
+
end
|
|
74
|
+
# in this scenario the right table has the 'highest' data,
|
|
75
|
+
# so 'right-sided' data are already implicitely tested here
|
|
76
|
+
diff.should == [
|
|
77
|
+
[:conflict, [
|
|
78
|
+
{'id' => 2, 'name' => 'Bob - left database version'},
|
|
79
|
+
{'id' => 2, 'name' => 'Bob - right database version'}]],
|
|
80
|
+
[:left, {'id' => 3, 'name' => 'Charlie - exists in left database only'}],
|
|
81
|
+
[:right, {'id' => 4, 'name' => 'Dave - exists in right database only'}],
|
|
82
|
+
[:left, {'id' => 5, 'name' => 'Eve - exists in left database only'}],
|
|
83
|
+
[:right, {'id' => 6, 'name' => 'Fred - exists in right database only'}]
|
|
84
|
+
]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "compare_blocks should destroy the created cursors" do
|
|
88
|
+
session = Session.new
|
|
89
|
+
|
|
90
|
+
left_cursor = get_block_cursor session.left, 'scanner_records', 0
|
|
91
|
+
right_cursor = get_block_cursor session.right, 'scanner_records', 0
|
|
92
|
+
|
|
93
|
+
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
94
|
+
scan.compare_blocks(left_cursor, right_cursor) { |type, row| }
|
|
95
|
+
|
|
96
|
+
session.left.cursors.should == {}
|
|
97
|
+
session.right.cursors.should == {}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "run should only call compare single rows if there are different block checksums" do
|
|
101
|
+
config = deep_copy(proxied_config)
|
|
102
|
+
config.right = config.left
|
|
103
|
+
session = Session.new config
|
|
104
|
+
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
105
|
+
scan.should_not_receive(:compare_blocks)
|
|
106
|
+
diff = []
|
|
107
|
+
scan.run do |type, row|
|
|
108
|
+
diff.push [type,row]
|
|
109
|
+
end
|
|
110
|
+
diff.should == []
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "run should compare all the records in the table" do
|
|
114
|
+
session = Session.new
|
|
115
|
+
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
116
|
+
diff = []
|
|
117
|
+
scan.run do |type, row|
|
|
118
|
+
diff.push [type, row]
|
|
119
|
+
end
|
|
120
|
+
# in this scenario the right table has the 'highest' data,
|
|
121
|
+
# so 'right-sided' data are already implicitely tested here
|
|
122
|
+
diff.should == [
|
|
123
|
+
[:conflict, [
|
|
124
|
+
{'id' => 2, 'name' => 'Bob - left database version'},
|
|
125
|
+
{'id' => 2, 'name' => 'Bob - right database version'}]],
|
|
126
|
+
[:left, {'id' => 3, 'name' => 'Charlie - exists in left database only'}],
|
|
127
|
+
[:right, {'id' => 4, 'name' => 'Dave - exists in right database only'}],
|
|
128
|
+
[:left, {'id' => 5, 'name' => 'Eve - exists in left database only'}],
|
|
129
|
+
[:right, {'id' => 6, 'name' => 'Fred - exists in right database only'}]
|
|
130
|
+
]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "run should update the progress" do
|
|
134
|
+
session = Session.new
|
|
135
|
+
scan = ProxiedTableScan.new session, 'scanner_records'
|
|
136
|
+
number_steps = 0
|
|
137
|
+
scan.should_receive(:update_progress).any_number_of_times do |steps|
|
|
138
|
+
number_steps += steps
|
|
139
|
+
end
|
|
140
|
+
scan.run {|_, _|}
|
|
141
|
+
number_steps.should == 8
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "run should update the progress even if there are no records" do
|
|
145
|
+
# it should do that to ensure the progress bar is printed
|
|
146
|
+
scan = ProxiedTableScan.new Session.new, 'extender_no_record'
|
|
147
|
+
scan.should_receive(:update_progress).at_least(:once)
|
|
148
|
+
scan.run {|_, _|}
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ProxyBlockCursor do
|
|
6
|
+
before(:each) do
|
|
7
|
+
@session = create_mock_proxy_connection 'dummy_table', ['dummy_id']
|
|
8
|
+
@cursor = ProxyBlockCursor.new @session, 'dummy_table'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "initialize should super to ProxyCursor" do
|
|
12
|
+
@cursor.table.should == 'dummy_table'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "next? should return true if there is an already loaded unprocessed row" do
|
|
16
|
+
@cursor.last_row = :dummy_row
|
|
17
|
+
@cursor.next?.should be_true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "next? should return true if the database cursor has more rows" do
|
|
21
|
+
table_cursor = mock("DBCursor")
|
|
22
|
+
table_cursor.should_receive(:next?).and_return(true)
|
|
23
|
+
@cursor.cursor = table_cursor
|
|
24
|
+
|
|
25
|
+
@cursor.next?.should be_true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "next? should return false if there are no loaded or unloaded unprocessed rows" do
|
|
29
|
+
table_cursor = mock("DBCursor")
|
|
30
|
+
table_cursor.should_receive(:next?).and_return(false)
|
|
31
|
+
@cursor.cursor = table_cursor
|
|
32
|
+
|
|
33
|
+
@cursor.next?.should be_false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "next_row should return last loaded unprocessed row or nil if there is none" do
|
|
37
|
+
@cursor.last_row = :dummy_row
|
|
38
|
+
|
|
39
|
+
@cursor.next_row.should == :dummy_row
|
|
40
|
+
@cursor.last_row.should be_nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "next_row should return next row in database if there is no loaded unprocessed row available" do
|
|
44
|
+
table_cursor = mock("DBCursor")
|
|
45
|
+
table_cursor.should_receive(:next_row).and_return(:dummy_row)
|
|
46
|
+
@cursor.cursor = table_cursor
|
|
47
|
+
|
|
48
|
+
@cursor.next_row.should == :dummy_row
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "reset_checksum should create a new empty SHA1 digest" do
|
|
52
|
+
@cursor.digest = :dummy_digest
|
|
53
|
+
@cursor.reset_checksum
|
|
54
|
+
@cursor.digest.should be_an_instance_of(Digest::SHA1)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "reset_checksum should reset block variables" do
|
|
58
|
+
@cursor.reset_checksum
|
|
59
|
+
@cursor.row_checksums.should == []
|
|
60
|
+
@cursor.current_row_cache_size.should == 0
|
|
61
|
+
@cursor.row_cache.should == {}
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "update_checksum should update the existing digests" do
|
|
66
|
+
dummy_row1 = {'dummy_id' => 'dummy_value1'}
|
|
67
|
+
dummy_row2 = {'dummy_id' => 'dummy_value2'}
|
|
68
|
+
|
|
69
|
+
@cursor.reset_checksum
|
|
70
|
+
@cursor.update_checksum dummy_row1
|
|
71
|
+
@cursor.update_checksum dummy_row2
|
|
72
|
+
|
|
73
|
+
@cursor.current_checksum.should == Digest::SHA1.hexdigest(Marshal.dump(dummy_row1) + Marshal.dump(dummy_row2))
|
|
74
|
+
@cursor.row_checksums.should == [
|
|
75
|
+
{:row_keys => dummy_row1, :checksum => Digest::SHA1.hexdigest(Marshal.dump(dummy_row1))},
|
|
76
|
+
{:row_keys => dummy_row2, :checksum => Digest::SHA1.hexdigest(Marshal.dump(dummy_row2))},
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
@cursor.row_cache.should == {
|
|
80
|
+
Digest::SHA1.hexdigest(Marshal.dump(dummy_row1)) => Marshal.dump(dummy_row1),
|
|
81
|
+
Digest::SHA1.hexdigest(Marshal.dump(dummy_row2)) => Marshal.dump(dummy_row2)
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "retrieve_row_cache should retrieve the specified elements" do
|
|
86
|
+
@cursor.row_cache = {'dummy_checksum' => 'bla'}
|
|
87
|
+
@cursor.retrieve_row_cache(['non_cached_row_checksum', 'dummy_checksum']).should ==
|
|
88
|
+
{'dummy_checksum' => 'bla'}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "current_checksum should return the current checksum" do
|
|
92
|
+
digest = mock("Digest")
|
|
93
|
+
digest.should_receive(:hexdigest).and_return(:dummy_checksum)
|
|
94
|
+
@cursor.digest = digest
|
|
95
|
+
|
|
96
|
+
@cursor.current_checksum.should == :dummy_checksum
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "checksum should reset the current digest" do
|
|
100
|
+
@cursor.reset_checksum # need to call it now so that for the call to checksum it can be mocked
|
|
101
|
+
@cursor.should_receive(:reset_checksum)
|
|
102
|
+
@cursor.should_receive(:next?).and_return(false)
|
|
103
|
+
@cursor.checksum :proxy_block_size => 1
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "checksum should complain if neither :proxy_block_size nor :max_row are provided" do
|
|
107
|
+
lambda {@cursor.checksum}.should raise_error(
|
|
108
|
+
RuntimeError, 'options must include either :proxy_block_size or :max_row')
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "checksum should verify options" do
|
|
112
|
+
lambda {@cursor.checksum}.should raise_error(
|
|
113
|
+
RuntimeError, 'options must include either :proxy_block_size or :max_row')
|
|
114
|
+
lambda {@cursor.checksum(:proxy_block_size => 0)}.should raise_error(
|
|
115
|
+
RuntimeError, ':proxy_block_size must be greater than 0')
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "checksum should read maximum :proxy_block_size rows" do
|
|
119
|
+
session = ProxyConnection.new proxied_config.left
|
|
120
|
+
|
|
121
|
+
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
122
|
+
cursor.prepare_fetch
|
|
123
|
+
|
|
124
|
+
last_row, = cursor.checksum :proxy_block_size => 2
|
|
125
|
+
last_row.should == {'id' => 2}
|
|
126
|
+
|
|
127
|
+
last_row, = cursor.checksum :proxy_block_size => 1000
|
|
128
|
+
last_row.should == {'id' => 5}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "checksum should read up to the specified :max_row" do
|
|
132
|
+
session = ProxyConnection.new proxied_config.left
|
|
133
|
+
|
|
134
|
+
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
135
|
+
cursor.prepare_fetch
|
|
136
|
+
|
|
137
|
+
last_row, = cursor.checksum :max_row => {'id' => 2}
|
|
138
|
+
last_row.should == {'id' => 2}
|
|
139
|
+
last_row, = cursor.checksum :max_row => {'id' => 1000}
|
|
140
|
+
last_row.should == {'id' => 5}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "checksum called with :proxy_block_size should return the correct checksum" do
|
|
144
|
+
session = ProxyConnection.new proxied_config.left
|
|
145
|
+
|
|
146
|
+
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
147
|
+
cursor.prepare_fetch
|
|
148
|
+
|
|
149
|
+
last_row , checksum = cursor.checksum :proxy_block_size => 2
|
|
150
|
+
|
|
151
|
+
expected_checksum = Digest::SHA1.hexdigest(
|
|
152
|
+
Marshal.dump('id' => 1, 'name' => 'Alice - exists in both databases') +
|
|
153
|
+
Marshal.dump('id' => 2, 'name' => 'Bob - left database version')
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
checksum.should == expected_checksum
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "checksum called with :max_row should return the correct checksum" do
|
|
160
|
+
session = ProxyConnection.new proxied_config.left
|
|
161
|
+
|
|
162
|
+
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
163
|
+
cursor.prepare_fetch
|
|
164
|
+
|
|
165
|
+
last_row , checksum = cursor.checksum :max_row => {'id' => 2}
|
|
166
|
+
|
|
167
|
+
expected_checksum = Digest::SHA1.hexdigest(
|
|
168
|
+
Marshal.dump('id' => 1, 'name' => 'Alice - exists in both databases') +
|
|
169
|
+
Marshal.dump('id' => 2, 'name' => 'Bob - left database version')
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
checksum.should == expected_checksum
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "checksum called with :proxy_block_size should return the correct row count" do
|
|
176
|
+
session = ProxyConnection.new proxied_config.left
|
|
177
|
+
|
|
178
|
+
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
179
|
+
cursor.prepare_fetch
|
|
180
|
+
|
|
181
|
+
_ , _, row_count = cursor.checksum :proxy_block_size => 2
|
|
182
|
+
|
|
183
|
+
row_count.should == 2
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "checksum called with :max_row should return the correct row count" do
|
|
187
|
+
session = ProxyConnection.new proxied_config.left
|
|
188
|
+
|
|
189
|
+
cursor = ProxyBlockCursor.new session, 'scanner_records'
|
|
190
|
+
cursor.prepare_fetch
|
|
191
|
+
|
|
192
|
+
_ , _, row_count = cursor.checksum :max_row => {'id' => 2}
|
|
193
|
+
|
|
194
|
+
row_count.should == 2
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
end
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ProxyConnection do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = proxied_config
|
|
8
|
+
@connection = ProxyConnection.new Initializer.configuration.left
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "initialize should connect to the database" do
|
|
12
|
+
(!!@connection.connection.active?).should == true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "initialize should store the configuratin" do
|
|
16
|
+
@connection.config.should == Initializer.configuration.left
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "destroy should disconnect from the database" do
|
|
20
|
+
if ActiveSupport.const_defined?(:Notifications)
|
|
21
|
+
ConnectionExtenders::install_logger @connection.connection, :logger => StringIO.new
|
|
22
|
+
log_subscriber = @connection.connection.log_subscriber
|
|
23
|
+
|
|
24
|
+
ActiveSupport::Notifications.notifier.listeners_for("sql.active_record").should include(log_subscriber)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@connection.destroy
|
|
28
|
+
|
|
29
|
+
if ActiveSupport.const_defined?(:Notifications)
|
|
30
|
+
ActiveSupport::Notifications.notifier.listeners_for("sql.active_record").should_not include(log_subscriber)
|
|
31
|
+
@connection.connection.log_subscriber.should be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
(!!@connection.connection.active?).should == false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "cursors should return the current cursor hash or an empty hash if nil" do
|
|
38
|
+
@connection.cursors.should == {}
|
|
39
|
+
@connection.cursors[:dummy_cursor] = :dummy_cursor
|
|
40
|
+
@connection.cursors.should == {:dummy_cursor => :dummy_cursor}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "save_cursor should register the provided cursor" do
|
|
44
|
+
@connection.save_cursor :dummy_cursor
|
|
45
|
+
|
|
46
|
+
@connection.cursors[:dummy_cursor].should == :dummy_cursor
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "destroy should destroy and unregister any stored cursors" do
|
|
50
|
+
cursor = mock("Cursor")
|
|
51
|
+
cursor.should_receive(:destroy)
|
|
52
|
+
|
|
53
|
+
@connection.save_cursor cursor
|
|
54
|
+
@connection.destroy
|
|
55
|
+
|
|
56
|
+
@connection.cursors.should == {}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "destroy_cursor should destroy and unregister the provided cursor" do
|
|
60
|
+
cursor = mock("Cursor")
|
|
61
|
+
cursor.should_receive(:destroy)
|
|
62
|
+
|
|
63
|
+
@connection.save_cursor cursor
|
|
64
|
+
@connection.destroy_cursor cursor
|
|
65
|
+
|
|
66
|
+
@connection.cursors.should == {}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "create_cursor should create and register the cursor and initiate row fetching" do
|
|
70
|
+
cursor = @connection.create_cursor(
|
|
71
|
+
ProxyRowCursor,
|
|
72
|
+
'scanner_records',
|
|
73
|
+
:from => {'id' => 2},
|
|
74
|
+
:to => {'id' => 2}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
cursor.should be_an_instance_of(ProxyRowCursor)
|
|
78
|
+
cursor.next_row_keys_and_checksum[0].should == {'id' => 2} # verify that 'from' range was used
|
|
79
|
+
cursor.next?.should be_false # verify that 'to' range was used
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "column_names should return the column names of the specified table" do
|
|
83
|
+
@connection.column_names('scanner_records').should == ['id', 'name']
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "column_names should cache the column names" do
|
|
87
|
+
@connection.column_names('scanner_records')
|
|
88
|
+
@connection.column_names('scanner_text_key')
|
|
89
|
+
@connection.connection.should_not_receive(:columns)
|
|
90
|
+
@connection.column_names('scanner_records').should == ['id', 'name']
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "primary_key_names should return the correct primary keys" do
|
|
94
|
+
@connection.primary_key_names('scanner_records').should == ['id']
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "primary_key_names should return the manual primary keys if they exist" do
|
|
98
|
+
@connection.stub!(:manual_primary_keys).
|
|
99
|
+
and_return({'scanner_records' => ['manual_key']})
|
|
100
|
+
@connection.primary_key_names('scanner_records').should == ['manual_key']
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "primary_key_names should not cache or manually overwrite if :raw option is given" do
|
|
104
|
+
@connection.stub!(:manual_primary_keys).
|
|
105
|
+
and_return({'scanner_records' => ['manual_key']})
|
|
106
|
+
key1 = @connection.primary_key_names('scanner_records', :raw => true)
|
|
107
|
+
key1.should == ['id']
|
|
108
|
+
|
|
109
|
+
key2 = @connection.primary_key_names('scanner_records', :raw => true)
|
|
110
|
+
key1.__id__.should_not == key2.__id__
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "primary_key_names should cache the primary primary keys" do
|
|
114
|
+
@connection.connection.should_receive(:primary_key_names) \
|
|
115
|
+
.with('dummy_table').once.and_return(['dummy_key'])
|
|
116
|
+
@connection.connection.should_receive(:primary_key_names) \
|
|
117
|
+
.with('dummy_table2').once.and_return(['dummy_key2'])
|
|
118
|
+
|
|
119
|
+
@connection.primary_key_names('dummy_table').should == ['dummy_key']
|
|
120
|
+
@connection.primary_key_names('dummy_table2').should == ['dummy_key2']
|
|
121
|
+
@connection.primary_key_names('dummy_table').should == ['dummy_key']
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Note:
|
|
125
|
+
# Additional select_cursor tests are executed via
|
|
126
|
+
# 'db_specific_connection_extenders_spec.rb'
|
|
127
|
+
# (To verify the behaviour for all supported databases)
|
|
128
|
+
|
|
129
|
+
it "select_cursor should return the result fetcher" do
|
|
130
|
+
fetcher = @connection.select_cursor(:table => 'scanner_records', :type_cast => false)
|
|
131
|
+
fetcher.connection.should == @connection
|
|
132
|
+
fetcher.options.should == {:table => 'scanner_records', :type_cast => false}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "select_cursor should return a type casting cursor if :type_cast option is specified" do
|
|
136
|
+
fetcher = @connection.select_cursor(:table => 'scanner_records', :type_cast => true)
|
|
137
|
+
fetcher.should be_an_instance_of(TypeCastingCursor)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "table_select_query should handle queries without any conditions" do
|
|
141
|
+
@connection.table_select_query('scanner_records') \
|
|
142
|
+
.should =~ sql_to_regexp("\
|
|
143
|
+
select 'id', 'name' from 'scanner_records'\
|
|
144
|
+
order by 'id'")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "table_select_query should handle queries with only a from condition" do
|
|
148
|
+
@connection.table_select_query('scanner_records', :from => {'id' => 1}) \
|
|
149
|
+
.should =~ sql_to_regexp("\
|
|
150
|
+
select 'id', 'name' from 'scanner_records' \
|
|
151
|
+
where ('id') >= (1) order by 'id'")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "table_select_query should handle queries with an exclusive from condition" do
|
|
155
|
+
@connection.table_select_query(
|
|
156
|
+
'scanner_records',
|
|
157
|
+
:from => {'id' => 1},
|
|
158
|
+
:exclude_starting_row => true
|
|
159
|
+
).should =~ sql_to_regexp("\
|
|
160
|
+
select 'id', 'name' from 'scanner_records' \
|
|
161
|
+
where ('id') > (1) order by 'id'")
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it "table_select_query should handle queries with only a to condition" do
|
|
165
|
+
@connection.table_select_query('scanner_text_key', :to => {'text_id' => 'k1'}) \
|
|
166
|
+
.should =~ sql_to_regexp("\
|
|
167
|
+
select 'text_id', 'name' from 'scanner_text_key' \
|
|
168
|
+
where ('text_id') <= ('k1') order by 'text_id'")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "table_select_query should handle queries with both from and to conditions" do
|
|
172
|
+
@connection.table_select_query('scanner_records',
|
|
173
|
+
:from => {'id' => 0}, :to => {'id' => 1}) \
|
|
174
|
+
.should =~ sql_to_regexp("\
|
|
175
|
+
select 'id', 'name' from 'scanner_records' \
|
|
176
|
+
where ('id') >= (0) and ('id') <= (1) order by 'id'")
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "table_select_query should handle queries for specific rows" do
|
|
180
|
+
@connection.table_select_query('scanner_records',
|
|
181
|
+
:row_keys => [{'id' => 0}, {'id' => 1}]) \
|
|
182
|
+
.should =~ sql_to_regexp("\
|
|
183
|
+
select 'id', 'name' from 'scanner_records' \
|
|
184
|
+
where ('id') in ((0), (1)) order by 'id'")
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "table_select_query should handle queries for specific rows with the row array actually being empty" do
|
|
188
|
+
@connection.table_select_query('scanner_records', :row_keys => []) \
|
|
189
|
+
.should =~ sql_to_regexp("\
|
|
190
|
+
select 'id', 'name' from 'scanner_records' \
|
|
191
|
+
where false order by 'id'")
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "table_select_query should handle queries for specific rows in combination with other conditions" do
|
|
195
|
+
@connection.table_select_query('scanner_records',
|
|
196
|
+
:from => {'id' => 0},
|
|
197
|
+
:row_keys => [{'id' => 1}, {'id' => 2}]) \
|
|
198
|
+
.should =~ sql_to_regexp("\
|
|
199
|
+
select 'id', 'name' from 'scanner_records' \
|
|
200
|
+
where ('id') >= (0) and ('id') in ((1), (2)) order by 'id'")
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "table_select_query should handle tables with combined primary keys" do
|
|
204
|
+
@connection.table_select_query('extender_combined_key',
|
|
205
|
+
:from => {'first_id' => 0, 'second_id' => 1},
|
|
206
|
+
:to => {'first_id' => 2, 'second_id' => 3}) \
|
|
207
|
+
.should =~ sql_to_regexp("\
|
|
208
|
+
select 'first_id', 'second_id', 'name' from 'extender_combined_key' \
|
|
209
|
+
where ('first_id', 'second_id') >= (0, 1) \
|
|
210
|
+
and ('first_id', 'second_id') <= (2, 3) \
|
|
211
|
+
order by 'first_id', 'second_id'")
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "table_select_query should quote column values" do
|
|
215
|
+
select_options = {:from => {'text_id' => 'a'}, :to => {'text_id' => 'b'}}
|
|
216
|
+
|
|
217
|
+
@connection.table_select_query('scanner_text_key', select_options) \
|
|
218
|
+
.should match(/'a'.*'b'/)
|
|
219
|
+
|
|
220
|
+
# additional check that the quoted query actually works
|
|
221
|
+
cursor = ProxyCursor.new(@connection, 'scanner_text_key')
|
|
222
|
+
results = cursor.prepare_fetch(select_options)
|
|
223
|
+
results.next_row.should == {'text_id' => 'a', 'name' => 'Alice'}
|
|
224
|
+
results.next_row.should == {'text_id' => 'b', 'name' => 'Bob'}
|
|
225
|
+
results.next?.should be_false
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "table_insert_query should return the correct SQL query" do
|
|
229
|
+
@connection.table_insert_query('scanner_records', 'name' => 'bla') \
|
|
230
|
+
.should =~ sql_to_regexp(%q!insert into "scanner_records"("name") values("bla")!)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "insert_record should insert the specified record" do
|
|
234
|
+
@connection.begin_db_transaction
|
|
235
|
+
begin
|
|
236
|
+
@connection.insert_record('scanner_records', 'id' => 9, 'name' => 'bla')
|
|
237
|
+
@connection.select_record(
|
|
238
|
+
:table => 'scanner_records',
|
|
239
|
+
:row_keys => ['id' => 9]
|
|
240
|
+
).should == {'id' => 9, 'name' => 'bla'}
|
|
241
|
+
ensure
|
|
242
|
+
@connection.rollback_db_transaction
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "insert_record should handle combined primary keys" do
|
|
247
|
+
@connection.begin_db_transaction
|
|
248
|
+
begin
|
|
249
|
+
@connection.insert_record('extender_combined_key', 'first_id' => 8, 'second_id' => '9')
|
|
250
|
+
@connection.select_record(
|
|
251
|
+
:table => 'extender_combined_key',
|
|
252
|
+
:row_keys => ['first_id' => 8, 'second_id' => 9]
|
|
253
|
+
).should == {'first_id' => 8, 'second_id' => 9, 'name' => nil}
|
|
254
|
+
ensure
|
|
255
|
+
@connection.rollback_db_transaction
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it "insert_record should write nil values correctly" do
|
|
260
|
+
@connection.begin_db_transaction
|
|
261
|
+
begin
|
|
262
|
+
@connection.insert_record('extender_combined_key', 'first_id' => 8, 'second_id' => '9', 'name' => nil)
|
|
263
|
+
@connection.select_record(
|
|
264
|
+
:table => 'extender_combined_key',
|
|
265
|
+
:row_keys => ['first_id' => 8, 'second_id' => 9]
|
|
266
|
+
).should == {'first_id' => 8, 'second_id' => 9, "name" => nil}
|
|
267
|
+
ensure
|
|
268
|
+
@connection.rollback_db_transaction
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it "insert_record should also insert uncommon data types correctly" do
|
|
273
|
+
@connection.begin_db_transaction
|
|
274
|
+
begin
|
|
275
|
+
test_data = {
|
|
276
|
+
'id' => 2,
|
|
277
|
+
'decimal_test' => 1.234,
|
|
278
|
+
'timestamp' => Time.local(2008,"jun",9,20,15,1),
|
|
279
|
+
'multi_byte' => "よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor.",
|
|
280
|
+
'binary_test' => Marshal.dump(['bla',:dummy,1,2,3]),
|
|
281
|
+
'text_test' => 'dummy text'
|
|
282
|
+
}
|
|
283
|
+
@connection.insert_record('extender_type_check', test_data)
|
|
284
|
+
|
|
285
|
+
cursor = @connection.select_cursor(
|
|
286
|
+
:table => 'extender_type_check',
|
|
287
|
+
:row_keys => [{'id' => 2}],
|
|
288
|
+
:type_cast => true
|
|
289
|
+
)
|
|
290
|
+
result_data = cursor.next_row
|
|
291
|
+
result_data.should == test_data
|
|
292
|
+
ensure
|
|
293
|
+
@connection.rollback_db_transaction
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it "table_update_query should return the correct SQL query" do
|
|
298
|
+
@connection.table_update_query('scanner_records', 'id' => 1) \
|
|
299
|
+
.should =~ sql_to_regexp(%q!update "scanner_records" set "id" = 1 where ("id") = (1)!)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it "update_record should update the specified record" do
|
|
303
|
+
@connection.begin_db_transaction
|
|
304
|
+
begin
|
|
305
|
+
@connection.update_record('scanner_records', 'id' => 1, 'name' => 'update_test')
|
|
306
|
+
@connection.select_record(
|
|
307
|
+
:table => "scanner_records",
|
|
308
|
+
:row_keys => ['id' => 1]
|
|
309
|
+
).should == {'id' => 1, 'name' => 'update_test'}
|
|
310
|
+
ensure
|
|
311
|
+
@connection.rollback_db_transaction
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "update_record should return the number of updated records" do
|
|
316
|
+
@connection.begin_db_transaction
|
|
317
|
+
begin
|
|
318
|
+
@connection.
|
|
319
|
+
update_record('scanner_records', 'id' => 1, 'name' => 'update_test').
|
|
320
|
+
should == 1
|
|
321
|
+
@connection.
|
|
322
|
+
update_record('scanner_records', 'id' => 0, 'name' => 'update_test').
|
|
323
|
+
should == 0
|
|
324
|
+
ensure
|
|
325
|
+
@connection.rollback_db_transaction
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it "update_record should handle combined primary keys" do
|
|
330
|
+
@connection.begin_db_transaction
|
|
331
|
+
begin
|
|
332
|
+
@connection.update_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1', 'name' => 'xy')
|
|
333
|
+
@connection.select_record(
|
|
334
|
+
:table => 'extender_combined_key',
|
|
335
|
+
:row_keys => ['first_id' => 1, 'second_id' => 1]
|
|
336
|
+
).should == {'first_id' => 1, 'second_id' => 1, 'name' => 'xy'}
|
|
337
|
+
ensure
|
|
338
|
+
@connection.rollback_db_transaction
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
it "update_record should handle key changes" do
|
|
343
|
+
@connection.begin_db_transaction
|
|
344
|
+
begin
|
|
345
|
+
@connection.update_record 'extender_combined_key',
|
|
346
|
+
{'first_id' => '8', 'second_id' => '9', 'name' => 'xy'},
|
|
347
|
+
{'first_id' => '1', 'second_id' => '1'}
|
|
348
|
+
@connection.select_record(
|
|
349
|
+
:table => 'extender_combined_key',
|
|
350
|
+
:row_keys => ['first_id' => 8, 'second_id' => 9]
|
|
351
|
+
).should == {'first_id' => 8, 'second_id' => 9, 'name' => 'xy'}
|
|
352
|
+
ensure
|
|
353
|
+
@connection.rollback_db_transaction
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it "update_record should write nil values correctly" do
|
|
358
|
+
@connection.begin_db_transaction
|
|
359
|
+
begin
|
|
360
|
+
@connection.update_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1', 'name' => nil)
|
|
361
|
+
@connection.select_record(
|
|
362
|
+
:table => 'extender_combined_key',
|
|
363
|
+
:row_keys => ['first_id' => 1, 'second_id' => 1]
|
|
364
|
+
).should == {'first_id' => 1, 'second_id' => 1, 'name' => nil}
|
|
365
|
+
ensure
|
|
366
|
+
@connection.rollback_db_transaction
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it "update_record should also update uncommon data types correctly" do
|
|
371
|
+
@connection.begin_db_transaction
|
|
372
|
+
begin
|
|
373
|
+
test_data = {
|
|
374
|
+
'id' => 1,
|
|
375
|
+
'decimal_test' => 0.234,
|
|
376
|
+
'timestamp' => Time.local(2009,"jun",9,20,15,1),
|
|
377
|
+
'multi_byte' => "よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor. bla",
|
|
378
|
+
'binary_test' => Marshal.dump(['bla',:dummy,1,2,3,4]),
|
|
379
|
+
'text_test' => 'dummy text bla'
|
|
380
|
+
}
|
|
381
|
+
@connection.update_record('extender_type_check', test_data)
|
|
382
|
+
|
|
383
|
+
@connection.select_record(
|
|
384
|
+
:table => "extender_type_check",
|
|
385
|
+
:row_keys => ["id" => 1]
|
|
386
|
+
).should == test_data
|
|
387
|
+
ensure
|
|
388
|
+
@connection.rollback_db_transaction
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
it "table_delete_query should return the correct SQL query" do
|
|
393
|
+
@connection.table_delete_query('scanner_records', 'id' => 1) \
|
|
394
|
+
.should =~ sql_to_regexp(%q!delete from "scanner_records" where ("id") = (1)!)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
it "delete_record should delete the specified record" do
|
|
398
|
+
@connection.begin_db_transaction
|
|
399
|
+
begin
|
|
400
|
+
@connection.delete_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1', 'name' => 'xy')
|
|
401
|
+
@connection.select_one(
|
|
402
|
+
"select first_id, second_id, name
|
|
403
|
+
from extender_combined_key where (first_id, second_id) = (1, 1)") \
|
|
404
|
+
.should be_nil
|
|
405
|
+
ensure
|
|
406
|
+
@connection.rollback_db_transaction
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it "delete_record should return the number of deleted records" do
|
|
411
|
+
@connection.begin_db_transaction
|
|
412
|
+
begin
|
|
413
|
+
@connection.
|
|
414
|
+
delete_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1').
|
|
415
|
+
should == 1
|
|
416
|
+
@connection.
|
|
417
|
+
delete_record('extender_combined_key', 'first_id' => 1, 'second_id' => '0').
|
|
418
|
+
should == 0
|
|
419
|
+
ensure
|
|
420
|
+
@connection.rollback_db_transaction
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|