bricolage-streamingload 0.14.2 → 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,31 +0,0 @@
1
- require 'test/unit'
2
- require 'bricolage/streamingload/dispatchermessage'
3
-
4
- module Bricolage::StreamingLoad
5
-
6
- class TestDispatcherMessage < Test::Unit::TestCase
7
-
8
- def new_s3event(message_id: nil, receipt_handle: nil, name: nil, time: nil, source: nil, region: nil, bucket: nil, key: nil, size: nil)
9
- S3ObjectDispatcherMessage.new(
10
- message_id: message_id,
11
- receipt_handle: receipt_handle,
12
- name: name,
13
- time: time,
14
- source: source,
15
- region: region,
16
- bucket: bucket,
17
- key: key,
18
- size: size
19
- )
20
- end
21
-
22
- test "#created?" do
23
- e = new_s3event(name: "ObjectCreated:Put")
24
- assert_true e.created_event?
25
- e = new_s3event(name: "ObjectCreated:Copy")
26
- assert_false e.created_event?
27
- end
28
-
29
- end
30
-
31
- end
@@ -1,620 +0,0 @@
1
- require 'test/unit'
2
- require 'bricolage/streamingload/job'
3
- require 'bricolage/context'
4
- require 'bricolage/logger'
5
-
6
- module Bricolage
7
-
8
- # FIXME: patch
9
- class NullLogger
10
- def log(*args) end
11
- def add(*args) end
12
- end
13
-
14
- module StreamingLoad
15
-
16
- class TestJob < Test::Unit::TestCase
17
-
18
- test "execute_task" do
19
- setup_context {|db|
20
- db.insert_into 'strload_tables', [1, 'testschema.desttable', 'testschema', 'desttable', 100, 1800, false]
21
- db.insert_into 'strload_tasks', [1, 'streaming_load_v3', 1, current_timestamp]
22
- db.insert_into 'strload_task_objects', [1, 1], [1, 2]
23
- db.insert_into 'strload_objects',
24
- [1, 's3://data-bucket/testschema.desttable/0001.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp],
25
- [2, 's3://data-bucket/testschema.desttable/0002.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp]
26
-
27
- job = new_job(task_id: 1, force: false)
28
- job.execute_task
29
-
30
- assert_equal [
31
- "begin transaction;",
32
- "copy testschema.desttable from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
33
- "insert into strload_load_logs (task_id, job_id, finish_time) values (1, #{job.job_id}, current_timestamp)",
34
- "commit;"
35
- ], job.data_ds.sql_list
36
-
37
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
38
- assert_equal 1, job_row['task_id'].to_i
39
- assert_equal job.process_id, job_row['process_id']
40
- assert_equal 'success', job_row['status']
41
- }
42
- end
43
-
44
- test "execute_task (with work table)" do
45
- setup_context {|db|
46
- db.insert_into 'strload_tables', [1, 'testschema.with_work_table', 'testschema', 'with_work_table', 100, 1800, false]
47
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
48
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
49
- db.insert_into 'strload_objects',
50
- [1001, 's3://data-bucket/testschema.with_work_table/0001.json.gz', 1024, 'testschema.with_work_table', 'mmmm', current_timestamp, current_timestamp],
51
- [1002, 's3://data-bucket/testschema.with_work_table/0002.json.gz', 1024, 'testschema.with_work_table', 'mmmm', current_timestamp, current_timestamp]
52
-
53
- job = new_job(task_id: 11, force: false)
54
- job.execute_task
55
-
56
- assert_equal [
57
- "begin transaction;",
58
- "delete from testschema.with_work_table_wk",
59
- "copy testschema.with_work_table_wk from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
60
- "insert into testschema.with_work_table select * from testschema.with_work_table_wk;\n",
61
- "insert into strload_load_logs (task_id, job_id, finish_time) values (11, #{job.job_id}, current_timestamp)",
62
- "truncate testschema.with_work_table_wk;"
63
- ], job.data_ds.sql_list
64
-
65
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
66
- assert_equal 11, job_row['task_id'].to_i
67
- assert_equal job.process_id, job_row['process_id']
68
- assert_equal 'success', job_row['status']
69
- }
70
- end
71
-
72
- test "execute_task (disabled)" do
73
- setup_context {|db|
74
- db.insert_into 'strload_tables', [1, 'testschema.desttable', 'testschema', 'desttable', 100, 1800, true]
75
- db.insert_into 'strload_tasks', [1, 'streaming_load_v3', 1, current_timestamp]
76
-
77
- job = new_job(task_id: 1, force: false)
78
- assert_raise(JobDefered) {
79
- job.execute_task
80
- }
81
- count = db.query_value("select count(*) from strload_jobs")
82
- assert_equal 0, count.to_i
83
- }
84
- end
85
-
86
- test "execute_task (duplicated)" do
87
- setup_context {|db|
88
- db.insert_into 'strload_tables', [1, 'testschema.desttable', 'testschema', 'desttable', 100, 1800, false]
89
- db.insert_into 'strload_tasks', [1, 'streaming_load_v3', 1, current_timestamp]
90
- db.insert_into 'strload_jobs',
91
- [1, 1, 'localhost-1234', 'failure', current_timestamp, current_timestamp, ''],
92
- [2, 1, 'localhost-1234', 'success', current_timestamp, current_timestamp, ''],
93
- [3, 1, 'localhost-1234', 'duplicated', current_timestamp, current_timestamp, '']
94
-
95
- job = new_job(task_id: 1, force: false)
96
- assert_raise(JobDuplicated) {
97
- job.execute_task
98
- }
99
- }
100
- end
101
-
102
- test "execute_task (duplicated but forced)" do
103
- setup_context {|db|
104
- db.insert_into 'strload_tables', [1, 'testschema.desttable', 'testschema', 'desttable', 100, 1800, false]
105
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
106
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
107
- db.insert_into 'strload_objects',
108
- [1001, 's3://data-bucket/testschema.desttable/0001.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp],
109
- [1002, 's3://data-bucket/testschema.desttable/0002.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp]
110
-
111
- job = new_job(task_id: 11, force: true)
112
- job.execute_task
113
-
114
- assert_equal [
115
- "begin transaction;",
116
- "copy testschema.desttable from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
117
- "insert into strload_load_logs (task_id, job_id, finish_time) values (11, #{job.job_id}, current_timestamp)",
118
- "commit;"
119
- ], job.data_ds.sql_list
120
-
121
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
122
- assert_equal 11, job_row['task_id'].to_i
123
- assert_equal job.process_id, job_row['process_id']
124
- assert_equal 'success', job_row['status']
125
- assert(/forced/ =~ job_row['message'])
126
- }
127
- end
128
-
129
- test "execute_task (load fails / first time)" do
130
- setup_context {|db|
131
- db.insert_into 'strload_tables', [1, 'testschema.sql_fails', 'testschema', 'sql_fails', 100, 1800, false]
132
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
133
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
134
- db.insert_into 'strload_objects',
135
- [1001, 's3://data-bucket/testschema.desttable/0001.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp],
136
- [1002, 's3://data-bucket/testschema.desttable/0002.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp]
137
-
138
- job = new_job(task_id: 11, force: false)
139
- assert_raise(JobFailure) {
140
- job.execute_task
141
- }
142
- assert_equal [
143
- "begin transaction;",
144
- "copy testschema.sql_fails from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
145
- "abort;"
146
- ], job.data_ds.sql_list
147
-
148
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
149
- assert_equal 11, job_row['task_id'].to_i
150
- assert_equal job.process_id, job_row['process_id']
151
- assert_equal 'failure', job_row['status']
152
- }
153
- end
154
-
155
- test "execute_task (load fails / nth time)" do
156
- setup_context {|db|
157
- db.insert_into 'strload_tables', [1, 'testschema.sql_fails', 'testschema', 'sql_fails', 100, 1800, false]
158
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
159
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
160
- db.insert_into 'strload_objects',
161
- [1001, 's3://data-bucket/testschema.sql_fails/0001.json.gz', 1024, 'testschema.sql_fails', 'mmmm', current_timestamp, current_timestamp],
162
- [1002, 's3://data-bucket/testschema.sql_fails/0002.json.gz', 1024, 'testschema.sql_fails', 'mmmm', current_timestamp, current_timestamp]
163
- db.insert_into 'strload_jobs',
164
- [101, 11, 'localhost-1234', 'failure', current_timestamp, current_timestamp, 'query failed']
165
-
166
- job = new_job(task_id: 11, force: false)
167
- assert_raise(JobFailure) {
168
- job.execute_task
169
- }
170
- assert_equal [
171
- "begin transaction;",
172
- "copy testschema.sql_fails from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
173
- "abort;"
174
- ], job.data_ds.sql_list
175
-
176
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
177
- assert_equal 11, job_row['task_id'].to_i
178
- assert_equal job.process_id, job_row['process_id']
179
- assert_equal 'failure', job_row['status']
180
- assert(/retry\#1/ =~ job_row['message'])
181
- }
182
- end
183
-
184
- test "execute_task (too many retry)" do
185
- setup_context {|db|
186
- db.insert_into 'strload_tables', [1, 'testschema.sql_fails', 'testschema', 'sql_fails', 100, 1800, false]
187
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
188
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
189
- db.insert_into 'strload_objects',
190
- [1001, 's3://data-bucket/testschema.sql_fails/0001.json.gz', 1024, 'testschema.sql_fails', 'mmmm', current_timestamp, current_timestamp],
191
- [1002, 's3://data-bucket/testschema.sql_fails/0002.json.gz', 1024, 'testschema.sql_fails', 'mmmm', current_timestamp, current_timestamp]
192
- db.insert_into 'strload_jobs',
193
- [101, 11, 'localhost-1234', 'failure', current_timestamp, current_timestamp, 'query failed'],
194
- [102, 11, 'localhost-1234', 'failure', current_timestamp, current_timestamp, 'retry#1 query failed'],
195
- [103, 11, 'localhost-1234', 'failure', current_timestamp, current_timestamp, 'retry#2 query failed'],
196
- [104, 11, 'localhost-1234', 'failure', current_timestamp, current_timestamp, 'retry#3 query failed'],
197
- [105, 11, 'localhost-1234', 'failure', current_timestamp, current_timestamp, 'retry#4 query failed']
198
-
199
- job = new_job(task_id: 11, force: false)
200
- assert_raise(JobCancelled) {
201
- job.execute_task
202
- }
203
- assert_equal [
204
- "begin transaction;",
205
- "copy testschema.sql_fails from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
206
- "abort;"
207
- ], job.data_ds.sql_list
208
-
209
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
210
- assert_equal 11, job_row['task_id'].to_i
211
- assert_equal job.process_id, job_row['process_id']
212
- assert_equal 'failure', job_row['status']
213
- assert(/retry\#5 FINAL/ =~ job_row['message'])
214
- }
215
- end
216
-
217
- test "execute_task (job error)" do
218
- setup_context {|db|
219
- db.insert_into 'strload_tables', [1, 'testschema.job_error', 'testschema', 'job_error', 100, 1800, false]
220
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
221
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
222
- db.insert_into 'strload_objects',
223
- [1001, 's3://data-bucket/testschema.job_error/0001.json.gz', 1024, 'testschema.job_error', 'mmmm', current_timestamp, current_timestamp],
224
- [1002, 's3://data-bucket/testschema.job_error/0002.json.gz', 1024, 'testschema.job_error', 'mmmm', current_timestamp, current_timestamp]
225
-
226
- job = new_job(task_id: 11, force: false)
227
- assert_raise(JobError) {
228
- job.execute_task
229
- }
230
- assert_equal [
231
- "begin transaction;",
232
- "copy testschema.job_error from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
233
- "abort;"
234
- ], job.data_ds.sql_list
235
-
236
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
237
- assert_equal 11, job_row['task_id'].to_i
238
- assert_equal job.process_id, job_row['process_id']
239
- assert_equal 'error', job_row['status']
240
- }
241
- end
242
-
243
- test "execute_task (unexpected error)" do
244
- setup_context {|db|
245
- db.insert_into 'strload_tables', [1, 'testschema.unexpected_error', 'testschema', 'unexpected_error', 100, 1800, false]
246
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
247
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
248
- db.insert_into 'strload_objects',
249
- [1001, 's3://data-bucket/testschema.unexpected_error/0001.json.gz', 1024, 'testschema.unexpected_error', 'mmmm', current_timestamp, current_timestamp],
250
- [1002, 's3://data-bucket/testschema.unexpected_error/0002.json.gz', 1024, 'testschema.unexpected_error', 'mmmm', current_timestamp, current_timestamp]
251
-
252
- job = new_job(task_id: 11, force: false)
253
- assert_raise(JobError) {
254
- job.execute_task
255
- }
256
- assert_equal [
257
- "begin transaction;",
258
- "copy testschema.unexpected_error from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
259
- "abort;"
260
- ], job.data_ds.sql_list
261
-
262
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
263
- assert_equal 11, job_row['task_id'].to_i
264
- assert_equal job.process_id, job_row['process_id']
265
- assert_equal 'error', job_row['status']
266
- }
267
- end
268
-
269
- test "execute_task (load error)" do
270
- setup_context {|db|
271
- db.insert_into 'strload_tables', [1, 'testschema.load_error', 'testschema', 'load_error', 100, 1800, false]
272
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
273
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
274
- db.insert_into 'strload_objects',
275
- [1001, 's3://data-bucket/testschema.desttable/0001.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp],
276
- [1002, 's3://data-bucket/testschema.desttable/0002.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp]
277
-
278
- job = new_job(task_id: 11, force: false)
279
- assert_raise(JobError) {
280
- job.execute_task
281
- }
282
- assert_equal [
283
- "begin transaction;",
284
- "copy testschema.load_error from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
285
- "abort;"
286
- ], job.data_ds.sql_list
287
-
288
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
289
- assert_equal 11, job_row['task_id'].to_i
290
- assert_equal job.process_id, job_row['process_id']
291
- assert_equal 'error', job_row['status']
292
- assert(/stl_load_errors/ =~ job_row['message'])
293
- }
294
- end
295
-
296
- test "execute_task (unknown status, really=success)" do
297
- setup_context {|db|
298
- db.insert_into 'strload_tables', [1, 'testschema.desttable', 'testschema', 'desttable', 100, 1800, false]
299
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
300
- db.insert_into 'strload_jobs',
301
- [101, 11, 'localhost-1234', 'unknown', current_timestamp, current_timestamp, 'data connection failed']
302
- @data_ds.provide_job_status 101, true
303
-
304
- job = new_job(task_id: 11, force: false)
305
- assert_raise(JobDuplicated) {
306
- job.execute_task
307
- }
308
-
309
- job_row = db.query_row("select * from strload_jobs where job_id = 101")
310
- assert_equal 'success', job_row['status']
311
- }
312
- end
313
-
314
- test "execute_task (unknown status, really=failure)" do
315
- setup_context {|db|
316
- db.insert_into 'strload_tables', [1, 'testschema.desttable', 'testschema', 'desttable', 100, 1800, false]
317
- db.insert_into 'strload_tasks', [11, 'streaming_load_v3', 1, current_timestamp]
318
- db.insert_into 'strload_task_objects', [11, 1001], [11, 1002]
319
- db.insert_into 'strload_objects',
320
- [1001, 's3://data-bucket/testschema.desttable/0001.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp],
321
- [1002, 's3://data-bucket/testschema.desttable/0002.json.gz', 1024, 'testschema.desttable', 'mmmm', current_timestamp, current_timestamp]
322
- db.insert_into 'strload_jobs',
323
- [101, 11, 'localhost-1234', 'unknown', current_timestamp, current_timestamp, 'data connection failed']
324
- @data_ds.provide_job_status 101, false
325
-
326
- job = new_job(task_id: 11, force: false)
327
- job.execute_task
328
-
329
- assert_equal [
330
- "begin transaction;",
331
- "copy testschema.desttable from '#{job.manifest.url}' credentials 'cccc' manifest statupdate false compupdate false json 'auto' gzip timeformat 'auto' dateformat 'auto' acceptanydate acceptinvchars ' ' truncatecolumns trimblanks ;",
332
- "insert into strload_load_logs (task_id, job_id, finish_time) values (11, #{job.job_id}, current_timestamp)",
333
- "commit;"
334
- ], job.data_ds.sql_list
335
-
336
- job_row = db.query_row("select * from strload_jobs where job_id = 101")
337
- assert_equal 'failure', job_row['status']
338
-
339
- job_row = db.query_row("select * from strload_jobs where job_id = #{job.job_id}")
340
- assert_equal 11, job_row['task_id'].to_i
341
- assert_equal job.process_id, job_row['process_id']
342
- assert_equal 'success', job_row['status']
343
- }
344
- end
345
-
346
- def setup_context(verbose: false)
347
- @ctx = Context.for_application('.', environment: 'test', logger: (verbose ? nil : NullLogger.new))
348
- @ctl_ds = @ctx.get_data_source('sql', 'dwhctl')
349
- @data_ds = @ctx.get_data_source('sql', 'db_data_mock')
350
- @ctl_ds.open {|conn|
351
- client = SQLClient.new(conn)
352
- clear_all_tables(client)
353
- yield client
354
- }
355
- end
356
-
357
- def new_job(task_id:, force:)
358
- Job.new(
359
- context: @ctx,
360
- ctl_ds: @ctl_ds,
361
- data_ds: @data_ds,
362
- logger: @ctx.logger,
363
- task_id: task_id,
364
- force: force
365
- )
366
- end
367
-
368
- # FIXME: database cleaner
369
- def clear_all_tables(client)
370
- client.truncate_tables %w[
371
- strload_tables
372
- strload_objects
373
- strload_task_objects
374
- strload_tasks
375
- strload_jobs
376
- ]
377
- end
378
-
379
- class SQLClient
380
- include SQLUtils
381
-
382
- def initialize(conn)
383
- @conn = conn
384
- end
385
-
386
- extend Forwardable
387
- def_delegators '@conn',
388
- :query,
389
- :query_value,
390
- :query_values,
391
- :query_row,
392
- :select,
393
- :update
394
-
395
- def insert_into(table, *records)
396
- sql = "insert into #{table}"
397
- sep = ' values '
398
- records.each do |rec|
399
- sql << sep; sep = ', '
400
- sql << format_values(rec)
401
- end
402
- @conn.update(sql)
403
- end
404
-
405
- def truncate_tables(tables)
406
- tables.each do |name|
407
- @conn.update("truncate #{name}")
408
- end
409
- end
410
-
411
- private
412
-
413
- def format_values(rec)
414
- '(' + rec.map {|val| format_value(val) }.join(', ') + ')'
415
- end
416
-
417
- def format_value(val)
418
- case val
419
- when nil then 'null'
420
- when true, false then val.to_s
421
- when Integer then val.to_s
422
- when SQLExpr then val.to_s
423
- when String then sql_string_literal(val)
424
- else
425
- raise ArgumentError, "unsupported value type: #{val.class}: #{val.inspect}"
426
- end
427
- end
428
-
429
- module DSL
430
- def null
431
- nil
432
- end
433
-
434
- def current_timestamp
435
- SQLExpr.new('current_timestamp')
436
- end
437
-
438
- def sql(expr)
439
- SQLExpr.new(expr)
440
- end
441
- end
442
-
443
- class SQLExpr
444
- def initialize(expr)
445
- @expr = expr
446
- end
447
-
448
- def to_s
449
- @expr
450
- end
451
- end
452
- end
453
-
454
- include SQLClient::DSL
455
-
456
- class PSQLDataSourceMock < DataSource
457
- declare_type 'psql_mock'
458
-
459
- def initialize(fail_pattern: nil, error_pattern: nil, exception_pattern: nil, load_error_pattern: nil, **params)
460
- @sql_list = []
461
- @fail_pattern = fail_pattern ? Regexp.compile(fail_pattern) : nil
462
- @error_pattern = error_pattern ? Regexp.compile(error_pattern) : nil
463
- @exception_pattern = exception_pattern ? Regexp.compile(exception_pattern) : nil
464
- @load_error_pattern = load_error_pattern ? Regexp.compile(load_error_pattern) : nil
465
- @job_status = {}
466
- end
467
-
468
- attr_reader :sql_list
469
-
470
- def open
471
- conn = Connection.new(self)
472
- if block_given?
473
- yield conn
474
- else
475
- conn
476
- end
477
- end
478
-
479
- def issue_sql(sql)
480
- logger.info "[mock] #{sql}"
481
- @sql_list.push sql
482
- if @fail_pattern and @fail_pattern =~ sql
483
- raise JobFailure, "query failed: #{sql}"
484
- end
485
- if @error_pattern and @error_pattern =~ sql
486
- raise JobError, "error"
487
- end
488
- if @exception_pattern and @exception_pattern =~ sql
489
- raise ArgumentError, "unexpected exception"
490
- end
491
- if @load_error_pattern and @load_error_pattern =~ sql
492
- raise JobError, "Load into table 'xxxx_table' failed. Check 'stl_load_errors' system table for details."
493
- end
494
- end
495
-
496
- def provide_job_status(job_id, succeeded)
497
- @job_status[job_id] = succeeded
498
- end
499
-
500
- def job_succeeded?(job_id)
501
- raise "job status unregistered: job_id=#{job_id}" unless @job_status.key?(job_id)
502
- @job_status[job_id]
503
- end
504
-
505
- class Connection
506
- def initialize(ds)
507
- @ds = ds
508
- end
509
-
510
- def query_value(sql)
511
- case sql
512
- when /\bstrload_load_logs where job_id = (\d+)/
513
- job_id = $1.to_i
514
- @ds.job_succeeded?(job_id) ? 1 : 0
515
- else
516
- raise "unknown query: #{sql}"
517
- end
518
- end
519
-
520
- def execute(sql)
521
- @ds.issue_sql sql
522
- end
523
-
524
- def transaction
525
- @ds.issue_sql "begin transaction;"
526
- txn = Transaction.new(@ds)
527
- yield txn
528
- rescue
529
- txn.abort unless txn.committed?
530
- raise
531
- ensure
532
- txn.commit unless txn.committed?
533
- end
534
- end
535
-
536
- class Transaction
537
- def initialize(ds)
538
- @ds = ds
539
- @commit = false
540
- end
541
-
542
- def committed?
543
- @commit
544
- end
545
-
546
- def commit
547
- @ds.issue_sql "commit;"
548
- @commit = true
549
- end
550
-
551
- def abort
552
- @ds.issue_sql "abort;"
553
- @commit = true
554
- end
555
-
556
- def truncate_and_commit(table)
557
- @ds.issue_sql "truncate #{table};"
558
- @commit = true
559
- end
560
- end
561
- end
562
-
563
- class S3DataSourceMock < DataSource
564
- declare_type 's3_mock'
565
-
566
- def initialize(**params)
567
- end
568
-
569
- def credential_string
570
- 'cccc'
571
- end
572
-
573
- def url(name)
574
- "s3://bucket/prefix/#{name}"
575
- end
576
-
577
- def object(name)
578
- ObjectMock.new(url(name), logger)
579
- end
580
-
581
- class ObjectMock
582
- def initialize(url, logger)
583
- @url = url
584
- @logger = logger
585
- end
586
-
587
- def put(body:)
588
- @logger.info "[mock] S3 PUT #{@url} content=#{body[0,20].inspect}..."
589
- end
590
-
591
- def delete
592
- @logger.info "[mock] S3 DELETE #{@url}"
593
- end
594
- end
595
- end
596
-
597
- test "TaskInfo#failure_count" do
598
- test_data = [
599
- [%w[], 0],
600
- [%w[success], 0],
601
- [%w[failure], 1],
602
- [%w[error], 1],
603
- [%w[failure failure], 2],
604
- [%w[failure error], 2],
605
- [%w[failure success], 0],
606
- [%w[success success], 0],
607
- [%w[failure success failure], 1],
608
- [%w[failure success failure success failure failure], 2]
609
- ]
610
- c = Job::ControlConnection
611
- test_data.each do |status_list, expected_count|
612
- task = c::TaskInfo.new(nil,nil,nil,nil,nil,nil, status_list.map {|st| c::JobInfo.new(nil, st) })
613
- assert_equal expected_count, task.failure_count
614
- end
615
- end
616
-
617
- end # class TestJob
618
-
619
- end # module StreamingLoad
620
- end # module Bricolage