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,399 @@
|
|
|
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
|
+
@connection.destroy
|
|
21
|
+
|
|
22
|
+
@connection.connection.active?.should == false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "refresh should not do anything if the connection is still active" do
|
|
26
|
+
ConnectionExtenders.should_not_receive(:db_connect)
|
|
27
|
+
@connection.refresh
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "refresh should reestablish the connection if it is no more active" do
|
|
31
|
+
@connection.destroy
|
|
32
|
+
@connection.refresh
|
|
33
|
+
@connection.connection.should be_active
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "cursors should return the current cursor hash or an empty hash if nil" do
|
|
37
|
+
@connection.cursors.should == {}
|
|
38
|
+
@connection.cursors[:dummy_cursor] = :dummy_cursor
|
|
39
|
+
@connection.cursors.should == {:dummy_cursor => :dummy_cursor}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "save_cursor should register the provided cursor" do
|
|
43
|
+
@connection.save_cursor :dummy_cursor
|
|
44
|
+
|
|
45
|
+
@connection.cursors[:dummy_cursor].should == :dummy_cursor
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "destroy should destroy and unregister any stored cursors" do
|
|
49
|
+
cursor = mock("Cursor")
|
|
50
|
+
cursor.should_receive(:destroy)
|
|
51
|
+
|
|
52
|
+
@connection.save_cursor cursor
|
|
53
|
+
@connection.destroy
|
|
54
|
+
|
|
55
|
+
@connection.cursors.should == {}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "destroy_cursor should destroy and unregister the provided cursor" do
|
|
59
|
+
cursor = mock("Cursor")
|
|
60
|
+
cursor.should_receive(:destroy)
|
|
61
|
+
|
|
62
|
+
@connection.save_cursor cursor
|
|
63
|
+
@connection.destroy_cursor cursor
|
|
64
|
+
|
|
65
|
+
@connection.cursors.should == {}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "create_cursor should create and register the cursor and initiate row fetching" do
|
|
69
|
+
cursor = @connection.create_cursor(
|
|
70
|
+
ProxyRowCursor,
|
|
71
|
+
'scanner_records',
|
|
72
|
+
:from => {'id' => 2},
|
|
73
|
+
:to => {'id' => 2}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
cursor.should be_an_instance_of(ProxyRowCursor)
|
|
77
|
+
cursor.next_row_keys_and_checksum[0].should == {'id' => 2} # verify that 'from' range was used
|
|
78
|
+
cursor.next?.should be_false # verify that 'to' range was used
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "column_names should return the column names of the specified table" do
|
|
82
|
+
@connection.column_names('scanner_records').should == ['id', 'name']
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "column_names should cache the column names" do
|
|
86
|
+
@connection.column_names('scanner_records')
|
|
87
|
+
@connection.column_names('scanner_text_key')
|
|
88
|
+
@connection.connection.should_not_receive(:columns)
|
|
89
|
+
@connection.column_names('scanner_records').should == ['id', 'name']
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "primary_key_names should return the correct primary keys" do
|
|
93
|
+
@connection.primary_key_names('scanner_records').should == ['id']
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "primary_key_names should return the manual primary keys if they exist" do
|
|
97
|
+
@connection.stub!(:manual_primary_keys).
|
|
98
|
+
and_return({'scanner_records' => ['manual_key']})
|
|
99
|
+
@connection.primary_key_names('scanner_records').should == ['manual_key']
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "primary_key_names should not cache or manually overwrite if :raw option is given" do
|
|
103
|
+
@connection.stub!(:manual_primary_keys).
|
|
104
|
+
and_return({'scanner_records' => ['manual_key']})
|
|
105
|
+
key1 = @connection.primary_key_names('scanner_records', :raw => true)
|
|
106
|
+
key1.should == ['id']
|
|
107
|
+
|
|
108
|
+
key2 = @connection.primary_key_names('scanner_records', :raw => true)
|
|
109
|
+
key1.__id__.should_not == key2.__id__
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "primary_key_names should cache the primary primary keys" do
|
|
113
|
+
@connection.connection.should_receive(:primary_key_names) \
|
|
114
|
+
.with('dummy_table').once.and_return(['dummy_key'])
|
|
115
|
+
@connection.connection.should_receive(:primary_key_names) \
|
|
116
|
+
.with('dummy_table2').once.and_return(['dummy_key2'])
|
|
117
|
+
|
|
118
|
+
@connection.primary_key_names('dummy_table').should == ['dummy_key']
|
|
119
|
+
@connection.primary_key_names('dummy_table2').should == ['dummy_key2']
|
|
120
|
+
@connection.primary_key_names('dummy_table').should == ['dummy_key']
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "select_cursor should forwarded the handed over query" do
|
|
124
|
+
@connection.connection.should_receive(:select_cursor).with('bla', 123)
|
|
125
|
+
@connection.select_cursor(:query => 'bla', :row_buffer_size => 123)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "select_cursor should use the default row buffer size if no explicit value is specified" do
|
|
129
|
+
@connection.connection.should_receive(:select_cursor) \
|
|
130
|
+
.with('bla', ProxyConnection::DEFAULT_ROW_BUFFER_SIZE)
|
|
131
|
+
@connection.select_cursor(:query => 'bla')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "select_cursor should construct the query and execute it" do
|
|
135
|
+
@connection.connection.should_receive(:select_cursor) \
|
|
136
|
+
.with(sql_to_regexp('select "id", "name" from "scanner_records" order by "id"'), ProxyConnection::DEFAULT_ROW_BUFFER_SIZE)
|
|
137
|
+
@connection.select_cursor(:table => 'scanner_records')
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "select_cursor should return a type casting cursor if :type_cast option is specified" do
|
|
141
|
+
@connection.select_cursor(:table => 'scanner_records').
|
|
142
|
+
should_not be_an_instance_of(TypeCastingCursor)
|
|
143
|
+
@connection.select_cursor(:table => 'scanner_records', :type_cast => true).
|
|
144
|
+
should be_an_instance_of(TypeCastingCursor)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "table_select_query should handle queries without any conditions" do
|
|
148
|
+
@connection.table_select_query('scanner_records') \
|
|
149
|
+
.should =~ sql_to_regexp("\
|
|
150
|
+
select 'id', 'name' from 'scanner_records'\
|
|
151
|
+
order by 'id'")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "table_select_query should handle queries with only a from condition" do
|
|
155
|
+
@connection.table_select_query('scanner_records', :from => {'id' => 1}) \
|
|
156
|
+
.should =~ sql_to_regexp("\
|
|
157
|
+
select 'id', 'name' from 'scanner_records' \
|
|
158
|
+
where ('id') >= (1) order by 'id'")
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "table_select_query should handle queries with an exclusive from condition" do
|
|
162
|
+
@connection.table_select_query(
|
|
163
|
+
'scanner_records',
|
|
164
|
+
:from => {'id' => 1},
|
|
165
|
+
:exclude_starting_row => true
|
|
166
|
+
).should =~ sql_to_regexp("\
|
|
167
|
+
select 'id', 'name' from 'scanner_records' \
|
|
168
|
+
where ('id') > (1) order by 'id'")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "table_select_query should handle queries with only a to condition" do
|
|
172
|
+
@connection.table_select_query('scanner_text_key', :to => {'text_id' => 'k1'}) \
|
|
173
|
+
.should =~ sql_to_regexp("\
|
|
174
|
+
select 'text_id', 'name' from 'scanner_text_key' \
|
|
175
|
+
where ('text_id') <= ('k1') order by 'text_id'")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it "table_select_query should handle queries with both from and to conditions" do
|
|
179
|
+
@connection.table_select_query('scanner_records',
|
|
180
|
+
:from => {'id' => 0}, :to => {'id' => 1}) \
|
|
181
|
+
.should =~ sql_to_regexp("\
|
|
182
|
+
select 'id', 'name' from 'scanner_records' \
|
|
183
|
+
where ('id') >= (0) and ('id') <= (1) order by 'id'")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "table_select_query should handle queries for specific rows" do
|
|
187
|
+
@connection.table_select_query('scanner_records',
|
|
188
|
+
:row_keys => [{'id' => 0}, {'id' => 1}]) \
|
|
189
|
+
.should =~ sql_to_regexp("\
|
|
190
|
+
select 'id', 'name' from 'scanner_records' \
|
|
191
|
+
where ('id') in ((0), (1)) order by 'id'")
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "table_select_query should handle queries for specific rows with the row array actually being empty" do
|
|
195
|
+
@connection.table_select_query('scanner_records', :row_keys => []) \
|
|
196
|
+
.should =~ sql_to_regexp("\
|
|
197
|
+
select 'id', 'name' from 'scanner_records' \
|
|
198
|
+
where false order by 'id'")
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "table_select_query should handle queries for specific rows in combination with other conditions" do
|
|
202
|
+
@connection.table_select_query('scanner_records',
|
|
203
|
+
:from => {'id' => 0},
|
|
204
|
+
:row_keys => [{'id' => 1}, {'id' => 2}]) \
|
|
205
|
+
.should =~ sql_to_regexp("\
|
|
206
|
+
select 'id', 'name' from 'scanner_records' \
|
|
207
|
+
where ('id') >= (0) and ('id') in ((1), (2)) order by 'id'")
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it "table_select_query should handle tables with combined primary keys" do
|
|
211
|
+
@connection.table_select_query('extender_combined_key',
|
|
212
|
+
:from => {'first_id' => 0, 'second_id' => 1},
|
|
213
|
+
:to => {'first_id' => 2, 'second_id' => 3}) \
|
|
214
|
+
.should =~ sql_to_regexp("\
|
|
215
|
+
select 'first_id', 'second_id', 'name' from 'extender_combined_key' \
|
|
216
|
+
where ('first_id', 'second_id') >= (0, 1) \
|
|
217
|
+
and ('first_id', 'second_id') <= (2, 3) \
|
|
218
|
+
order by 'first_id', 'second_id'")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "table_select_query should quote column values" do
|
|
222
|
+
select_options = {:from => {'text_id' => 'a'}, :to => {'text_id' => 'b'}}
|
|
223
|
+
|
|
224
|
+
@connection.table_select_query('scanner_text_key', select_options) \
|
|
225
|
+
.should match(/'a'.*'b'/)
|
|
226
|
+
|
|
227
|
+
# additional check that the quoted query actually works
|
|
228
|
+
cursor = ProxyCursor.new(@connection, 'scanner_text_key')
|
|
229
|
+
results = cursor.prepare_fetch(select_options)
|
|
230
|
+
results.next_row.should == {'text_id' => 'a', 'name' => 'Alice'}
|
|
231
|
+
results.next_row.should == {'text_id' => 'b', 'name' => 'Bob'}
|
|
232
|
+
results.next?.should be_false
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "table_insert_query should return the correct SQL query" do
|
|
236
|
+
@connection.table_insert_query('scanner_records', 'name' => 'bla') \
|
|
237
|
+
.should =~ sql_to_regexp(%q!insert into "scanner_records"("name") values("bla")!)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "insert_record should insert the specified record" do
|
|
241
|
+
@connection.begin_db_transaction
|
|
242
|
+
begin
|
|
243
|
+
@connection.insert_record('scanner_records', 'id' => 9, 'name' => 'bla')
|
|
244
|
+
@connection.select_one("select * from scanner_records where id = 9") \
|
|
245
|
+
.should == {'id' => '9', 'name' => 'bla'}
|
|
246
|
+
ensure
|
|
247
|
+
@connection.rollback_db_transaction
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "insert_record should handle combined primary keys" do
|
|
252
|
+
@connection.begin_db_transaction
|
|
253
|
+
begin
|
|
254
|
+
@connection.insert_record('extender_combined_key', 'first_id' => 8, 'second_id' => '9')
|
|
255
|
+
@connection.select_one(
|
|
256
|
+
"select first_id, second_id
|
|
257
|
+
from extender_combined_key where (first_id, second_id) = (8, 9)") \
|
|
258
|
+
.should == {'first_id' => '8', 'second_id' => '9'}
|
|
259
|
+
ensure
|
|
260
|
+
@connection.rollback_db_transaction
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it "insert_record should write nil values correctly" do
|
|
265
|
+
@connection.begin_db_transaction
|
|
266
|
+
begin
|
|
267
|
+
@connection.insert_record('extender_combined_key', 'first_id' => 8, 'second_id' => '9', 'name' => nil)
|
|
268
|
+
@connection.select_one(
|
|
269
|
+
"select first_id, second_id, name
|
|
270
|
+
from extender_combined_key where (first_id, second_id) = (8, 9)") \
|
|
271
|
+
.should == {'first_id' => '8', 'second_id' => '9', "name" => nil}
|
|
272
|
+
ensure
|
|
273
|
+
@connection.rollback_db_transaction
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it "insert_record should also insert uncommon data types correctly" do
|
|
278
|
+
@connection.begin_db_transaction
|
|
279
|
+
begin
|
|
280
|
+
test_data = {
|
|
281
|
+
'id' => 2,
|
|
282
|
+
'decimal_test' => 1.234,
|
|
283
|
+
'timestamp' => Time.local(2008,"jun",9,20,15,1),
|
|
284
|
+
'multi_byte' => "よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor.",
|
|
285
|
+
'binary_test' => Marshal.dump(['bla',:dummy,1,2,3]),
|
|
286
|
+
'text_test' => 'dummy text'
|
|
287
|
+
}
|
|
288
|
+
@connection.insert_record('extender_type_check', test_data)
|
|
289
|
+
|
|
290
|
+
cursor = @connection.select_cursor(
|
|
291
|
+
:table => 'extender_type_check',
|
|
292
|
+
:row_keys => [{'id' => 2}],
|
|
293
|
+
:type_cast => true
|
|
294
|
+
)
|
|
295
|
+
result_data = cursor.next_row
|
|
296
|
+
result_data.should == test_data
|
|
297
|
+
ensure
|
|
298
|
+
@connection.rollback_db_transaction
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it "table_update_query should return the correct SQL query" do
|
|
303
|
+
@connection.table_update_query('scanner_records', 'id' => 1) \
|
|
304
|
+
.should =~ sql_to_regexp(%q!update "scanner_records" set "id" = 1 where ("id") = (1)!)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it "update_record should update the specified record" do
|
|
308
|
+
@connection.begin_db_transaction
|
|
309
|
+
begin
|
|
310
|
+
@connection.update_record('scanner_records', 'id' => 1, 'name' => 'update_test')
|
|
311
|
+
@connection.select_one("select * from scanner_records where id = 1") \
|
|
312
|
+
.should == {'id' => '1', 'name' => 'update_test'}
|
|
313
|
+
ensure
|
|
314
|
+
@connection.rollback_db_transaction
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "update_record should handle combined primary keys" do
|
|
319
|
+
@connection.begin_db_transaction
|
|
320
|
+
begin
|
|
321
|
+
@connection.update_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1', 'name' => 'xy')
|
|
322
|
+
@connection.select_one(
|
|
323
|
+
"select first_id, second_id, name
|
|
324
|
+
from extender_combined_key where (first_id, second_id) = (1, 1)") \
|
|
325
|
+
.should == {'first_id' => '1', 'second_id' => '1', 'name' => 'xy'}
|
|
326
|
+
ensure
|
|
327
|
+
@connection.rollback_db_transaction
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it "update_record should handle key changes" do
|
|
332
|
+
@connection.begin_db_transaction
|
|
333
|
+
begin
|
|
334
|
+
@connection.update_record 'extender_combined_key',
|
|
335
|
+
{'first_id' => '8', 'second_id' => '9', 'name' => 'xy'},
|
|
336
|
+
{'first_id' => '1', 'second_id' => '1'}
|
|
337
|
+
@connection.select_one(
|
|
338
|
+
"select first_id, second_id, name
|
|
339
|
+
from extender_combined_key where (first_id, second_id) = (8, 9)") \
|
|
340
|
+
.should == {'first_id' => '8', 'second_id' => '9', 'name' => 'xy'}
|
|
341
|
+
ensure
|
|
342
|
+
@connection.rollback_db_transaction
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
it "update_record should write nil values correctly" do
|
|
347
|
+
@connection.begin_db_transaction
|
|
348
|
+
begin
|
|
349
|
+
@connection.update_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1', 'name' => nil)
|
|
350
|
+
@connection.select_one(
|
|
351
|
+
"select first_id, second_id, name
|
|
352
|
+
from extender_combined_key where (first_id, second_id) = (1, 1)") \
|
|
353
|
+
.should == {'first_id' => '1', 'second_id' => '1', 'name' => nil}
|
|
354
|
+
ensure
|
|
355
|
+
@connection.rollback_db_transaction
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
it "update_record should also update uncommon data types correctly" do
|
|
360
|
+
@connection.begin_db_transaction
|
|
361
|
+
begin
|
|
362
|
+
test_data = {
|
|
363
|
+
'id' => 1,
|
|
364
|
+
'decimal_test' => 0.234,
|
|
365
|
+
'timestamp' => Time.local(2009,"jun",9,20,15,1),
|
|
366
|
+
'multi_byte' => "よろしくお願(ねが)いします yoroshiku onegai shimasu: I humbly ask for your favor. bla",
|
|
367
|
+
'binary_test' => Marshal.dump(['bla',:dummy,1,2,3,4]),
|
|
368
|
+
'text_test' => 'dummy text bla'
|
|
369
|
+
}
|
|
370
|
+
@connection.update_record('extender_type_check', test_data)
|
|
371
|
+
|
|
372
|
+
org_cursor = @connection.select_cursor(:query => "select * from extender_type_check where id = 1")
|
|
373
|
+
cursor = TypeCastingCursor.new @connection, 'extender_type_check', org_cursor
|
|
374
|
+
result_data = cursor.next_row
|
|
375
|
+
result_data.should == test_data
|
|
376
|
+
ensure
|
|
377
|
+
@connection.rollback_db_transaction
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
it "table_delete_query should return the correct SQL query" do
|
|
382
|
+
@connection.table_delete_query('scanner_records', 'id' => 1) \
|
|
383
|
+
.should =~ sql_to_regexp(%q!delete from "scanner_records" where ("id") = (1)!)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it "delete_record should delete the specified record" do
|
|
387
|
+
@connection.begin_db_transaction
|
|
388
|
+
begin
|
|
389
|
+
@connection.delete_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1', 'name' => 'xy')
|
|
390
|
+
@connection.select_one(
|
|
391
|
+
"select first_id, second_id, name
|
|
392
|
+
from extender_combined_key where (first_id, second_id) = (1, 1)") \
|
|
393
|
+
.should be_nil
|
|
394
|
+
ensure
|
|
395
|
+
@connection.rollback_db_transaction
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ProxyCursor do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = proxied_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initialize should store session and table and cache the primary keys of table" do
|
|
11
|
+
connection = create_mock_proxy_connection 'dummy_table', ['dummy_key']
|
|
12
|
+
|
|
13
|
+
cursor = ProxyCursor.new connection, 'dummy_table'
|
|
14
|
+
|
|
15
|
+
cursor.connection.should == connection
|
|
16
|
+
cursor.table.should == 'dummy_table'
|
|
17
|
+
cursor.primary_key_names.should == ['dummy_key']
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "prepare_fetch should initiate the query and wrap it for type casting" do
|
|
21
|
+
connection = ProxyConnection.new Initializer.configuration.left
|
|
22
|
+
|
|
23
|
+
cursor = ProxyCursor.new(connection, 'scanner_records')
|
|
24
|
+
cursor.prepare_fetch
|
|
25
|
+
cursor.cursor.should be_an_instance_of(TypeCastingCursor)
|
|
26
|
+
cursor.cursor.next_row.should == {'id' => 1, 'name' => 'Alice - exists in both databases'}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "prepare_fetch called with option :row_keys should initiate the correct query" do
|
|
30
|
+
# Note: I am testing row_keys exclusively to make sure that this type of
|
|
31
|
+
# sub query will work correctly on all supported databases
|
|
32
|
+
connection = ProxyConnection.new Initializer.configuration.left
|
|
33
|
+
|
|
34
|
+
cursor = ProxyCursor.new(connection, 'extender_combined_key')
|
|
35
|
+
cursor.prepare_fetch :row_keys => [
|
|
36
|
+
{'first_id' => 1, 'second_id' => 1},
|
|
37
|
+
{'first_id' => 1, 'second_id' => 2}
|
|
38
|
+
]
|
|
39
|
+
cursor.cursor.next_row.should == {'first_id' => 1, 'second_id' => 1, 'name' => 'aa'}
|
|
40
|
+
cursor.cursor.next_row.should == {'first_id' => 1, 'second_id' => 2, 'name' => 'ab'}
|
|
41
|
+
cursor.cursor.next?.should == false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
it "destroy should clear and nil the cursor" do
|
|
46
|
+
connection = create_mock_proxy_connection 'dummy_table', ['dummy_key']
|
|
47
|
+
cursor = ProxyCursor.new connection, 'dummy_table'
|
|
48
|
+
|
|
49
|
+
table_cursor = mock("DBCursor")
|
|
50
|
+
table_cursor.should_receive(:clear)
|
|
51
|
+
cursor.cursor = table_cursor
|
|
52
|
+
|
|
53
|
+
cursor.destroy
|
|
54
|
+
cursor.cursor.should be_nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ProxyRowCursor do
|
|
6
|
+
before(:each) do
|
|
7
|
+
Initializer.configuration = standard_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "initialize should super to ProxyCursor" do
|
|
11
|
+
session = create_mock_proxy_connection 'dummy_table', ['dummy_id']
|
|
12
|
+
cursor = ProxyRowCursor.new session, 'dummy_table'
|
|
13
|
+
cursor.table.should == 'dummy_table'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "next? should delegate to the DB cursor" do
|
|
17
|
+
session = create_mock_proxy_connection 'dummy_table', ['dummy_id']
|
|
18
|
+
cursor = ProxyRowCursor.new session, 'dummy_table'
|
|
19
|
+
|
|
20
|
+
table_cursor = mock("DBCursor")
|
|
21
|
+
table_cursor.should_receive(:next?).and_return(true)
|
|
22
|
+
cursor.cursor = table_cursor
|
|
23
|
+
|
|
24
|
+
cursor.next?.should == true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "next_row should return the next row in the cursor" do
|
|
28
|
+
session = create_mock_proxy_connection 'dummy_table', ['dummy_id']
|
|
29
|
+
cursor = ProxyRowCursor.new session, 'dummy_table'
|
|
30
|
+
|
|
31
|
+
table_cursor = mock("DBCursor")
|
|
32
|
+
table_cursor.should_receive(:next_row).and_return(:dummy_row)
|
|
33
|
+
cursor.cursor = table_cursor
|
|
34
|
+
|
|
35
|
+
cursor.next_row.should == :dummy_row
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "next_row_keys_and_checksum should store the found row under current_row" do
|
|
39
|
+
session = create_mock_proxy_connection 'dummy_table', ['dummy_id']
|
|
40
|
+
cursor = ProxyRowCursor.new session, 'dummy_table'
|
|
41
|
+
|
|
42
|
+
table_cursor = mock("DBCursor")
|
|
43
|
+
table_cursor.should_receive(:next_row).and_return('dummy_id' => 'dummy_value')
|
|
44
|
+
|
|
45
|
+
cursor.cursor = table_cursor
|
|
46
|
+
cursor.next_row_keys_and_checksum
|
|
47
|
+
cursor.current_row.should == {'dummy_id' => 'dummy_value'}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "next_row_keys_and_checksum should returns the primary_keys and checksum of the found row" do
|
|
51
|
+
session = ProxyConnection.new proxied_config.left
|
|
52
|
+
|
|
53
|
+
cursor = ProxyRowCursor.new session, 'scanner_records'
|
|
54
|
+
cursor.prepare_fetch
|
|
55
|
+
|
|
56
|
+
keys, checksum = cursor.next_row_keys_and_checksum
|
|
57
|
+
|
|
58
|
+
expected_checksum = Digest::SHA1.hexdigest(
|
|
59
|
+
Marshal.dump('id' => 1, 'name' => 'Alice - exists in both databases')
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
keys.should == {'id' => 1}
|
|
63
|
+
checksum.should == expected_checksum
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include RR
|
|
4
|
+
|
|
5
|
+
describe ProxyRunner do
|
|
6
|
+
before(:each) do
|
|
7
|
+
DRb.stub!(:start_service)
|
|
8
|
+
DRb.thread.stub!(:join)
|
|
9
|
+
$stderr.stub!(:puts)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "get_options should return options as nil and status as 1 if command line parameters are unknown" do
|
|
13
|
+
# also verify that an error message is printed
|
|
14
|
+
$stderr.should_receive(:puts).any_number_of_times
|
|
15
|
+
options, status = ProxyRunner.new.get_options ["--nonsense"]
|
|
16
|
+
options.should == nil
|
|
17
|
+
status.should == 1
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "get_options should return options as nil and status as 0 if command line includes '--help'" do
|
|
21
|
+
# also verify that the help message is printed
|
|
22
|
+
$stderr.should_receive(:puts)
|
|
23
|
+
options, status = ProxyRunner.new.get_options ["--help"]
|
|
24
|
+
options.should == nil
|
|
25
|
+
status.should == 0
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "get_options should return the default options if none were given on the command line" do
|
|
29
|
+
options, status = ProxyRunner.new.get_options []
|
|
30
|
+
options.should == ProxyRunner::DEFAULT_OPTIONS
|
|
31
|
+
status.should == 0
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "get_options should return :host and :port options as per given command line" do
|
|
35
|
+
options, status = ProxyRunner.new.get_options ["--host", "127.0.0.1", "--port", "1234"]
|
|
36
|
+
options.should == {:host => '127.0.0.1', :port => 1234}
|
|
37
|
+
status.should == 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "construct_url should create the correct druby URL" do
|
|
41
|
+
ProxyRunner.new.build_url(:host => '127.0.0.1', :port => '1234').should == "druby://127.0.0.1:1234"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "start_server should create a DatabaseProxy and start the DRB server" do
|
|
45
|
+
DatabaseProxy.should_receive(:new)
|
|
46
|
+
DRb.should_receive(:start_service,"druby://127.0.0.1:1234")
|
|
47
|
+
DRb.stub!(:thread).and_return(Object.new)
|
|
48
|
+
DRb.thread.should_receive(:join)
|
|
49
|
+
ProxyRunner.new.start_server("druby://127.0.0.1:1234")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "run should not start a server if the command line is invalid" do
|
|
53
|
+
DRb.should_not_receive(:start_service)
|
|
54
|
+
DRb.stub!(:thread).and_return(Object.new)
|
|
55
|
+
DRb.thread.should_not_receive(:join)
|
|
56
|
+
ProxyRunner.run("--nonsense")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "run should start a server if the command line is correct" do
|
|
60
|
+
DRb.should_receive(:start_service)
|
|
61
|
+
DRb.stub!(:thread).and_return(Object.new)
|
|
62
|
+
DRb.thread.should_receive(:join)
|
|
63
|
+
ProxyRunner.run(["--port=1234"])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should register itself with CommandRunner" do
|
|
67
|
+
CommandRunner.commands['proxy'][:command].should == ProxyRunner
|
|
68
|
+
CommandRunner.commands['proxy'][:description].should be_an_instance_of(String)
|
|
69
|
+
end
|
|
70
|
+
end
|