baza.rb 0.8.0 → 0.9.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.
- checksums.yaml +4 -4
- data/lib/baza-rb/version.rb +1 -1
- data/lib/baza-rb.rb +271 -336
- data/test/test_baza-rb.rb +76 -36
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ccb82fa9b3f6e02cf08f46538505c63160250cf81e85f15a277ea2fad06d87a
|
4
|
+
data.tar.gz: 198aa9725055cb44737406ed098dbcbec7c659d2e180a1d45b84e0a4dc5f30ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a395f8bd4cf34bee034ba0a7c42d0021eddcf4f9e106fe3bc20efc37c55f0a5d6394a8ca50f47a6e2d1f20b1ba2ef20df263908bc7077afe1302a63d4d3422ed
|
7
|
+
data.tar.gz: 1a9c14cdef37a10ed2742da23ba483e0f3163b2d3c6f9011a37e6480acf0ab5e05daef4f6d629ee77fd40c7ac61a642ce34edea158378cf9e55fe43e19c46be9
|
data/lib/baza-rb/version.rb
CHANGED
data/lib/baza-rb.rb
CHANGED
@@ -40,6 +40,9 @@ class BazaRb
|
|
40
40
|
# Unexpected response arrived from the server.
|
41
41
|
class BadResponse < StandardError; end
|
42
42
|
|
43
|
+
# When server sent incorrectly compressed data.
|
44
|
+
class BadCompression < StandardError; end
|
45
|
+
|
43
46
|
# Initialize a new Zerocracy API client.
|
44
47
|
#
|
45
48
|
# @param [String] host The API host name (e.g., 'api.zerocracy.com')
|
@@ -68,15 +71,7 @@ class BazaRb
|
|
68
71
|
def whoami
|
69
72
|
nick = nil
|
70
73
|
elapsed(@loog) do
|
71
|
-
ret =
|
72
|
-
retry_it do
|
73
|
-
checked(
|
74
|
-
Typhoeus::Request.get(
|
75
|
-
home.append('whoami').to_s,
|
76
|
-
headers:
|
77
|
-
)
|
78
|
-
)
|
79
|
-
end
|
74
|
+
ret = get(home.append('whoami'))
|
80
75
|
nick = ret.body
|
81
76
|
throw :"I know that I am @#{nick}, at #{@host}"
|
82
77
|
end
|
@@ -90,15 +85,7 @@ class BazaRb
|
|
90
85
|
def balance
|
91
86
|
z = nil
|
92
87
|
elapsed(@loog) do
|
93
|
-
ret =
|
94
|
-
retry_it do
|
95
|
-
checked(
|
96
|
-
Typhoeus::Request.get(
|
97
|
-
home.append('account').append('balance').to_s,
|
98
|
-
headers:
|
99
|
-
)
|
100
|
-
)
|
101
|
-
end
|
88
|
+
ret = get(home.append('account').append('balance'))
|
102
89
|
z = ret.body.to_f
|
103
90
|
throw :"The balance is Ƶ#{z}, at #{@host}"
|
104
91
|
end
|
@@ -110,41 +97,27 @@ class BazaRb
|
|
110
97
|
# @param [String] name The unique name of the job on the server
|
111
98
|
# @param [String] data The binary data to push to the server (factbase content)
|
112
99
|
# @param [Array<String>] meta List of metadata strings to attach to the job
|
113
|
-
# @
|
100
|
+
# @param [Integer] chunk_size Maximum size of one chunk
|
114
101
|
# @raise [ServerFailure] If the push operation fails
|
115
|
-
def push(name, data, meta)
|
102
|
+
def push(name, data, meta, chunk_size: 1_000_000)
|
116
103
|
raise 'The "name" of the job is nil' if name.nil?
|
117
104
|
raise 'The "name" of the job may not be empty' if name.empty?
|
118
105
|
raise 'The "data" of the job is nil' if data.nil?
|
119
106
|
raise 'The "meta" of the job is nil' if meta.nil?
|
120
|
-
id = 0
|
121
|
-
hdrs = headers.merge(
|
122
|
-
'Content-Type' => 'application/octet-stream',
|
123
|
-
'Content-Length' => data.bytesize
|
124
|
-
)
|
125
|
-
unless meta.empty?
|
126
|
-
hdrs = hdrs.merge('X-Zerocracy-Meta' => meta.map { |v| Base64.encode64(v).delete("\n") }.join(' '))
|
127
|
-
end
|
128
|
-
params = {
|
129
|
-
connecttimeout: @timeout,
|
130
|
-
timeout: @timeout,
|
131
|
-
body: data,
|
132
|
-
headers: hdrs
|
133
|
-
}
|
134
107
|
elapsed(@loog) do
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
)
|
142
|
-
)
|
143
|
-
|
144
|
-
|
145
|
-
|
108
|
+
Tempfile.open do |file|
|
109
|
+
File.binwrite(file.path, data)
|
110
|
+
upload(
|
111
|
+
home.append('push').append(name),
|
112
|
+
file.path,
|
113
|
+
headers.merge(
|
114
|
+
'X-Zerocracy-Meta' => meta.map { |v| Base64.encode64(v).delete("\n") }.join(' ')
|
115
|
+
),
|
116
|
+
chunk_size:
|
117
|
+
)
|
118
|
+
end
|
119
|
+
throw :"Pushed #{data.bytesize} bytes to #{@host}"
|
146
120
|
end
|
147
|
-
id
|
148
121
|
end
|
149
122
|
|
150
123
|
# Pull factbase from the server for a specific job.
|
@@ -158,7 +131,7 @@ class BazaRb
|
|
158
131
|
data = ''
|
159
132
|
elapsed(@loog) do
|
160
133
|
Tempfile.open do |file|
|
161
|
-
download(home.append('pull').append("#{id}.fb")
|
134
|
+
download(home.append('pull').append("#{id}.fb"), file.path)
|
162
135
|
data = File.binread(file)
|
163
136
|
throw :"Pulled #{data.bytesize} bytes of job ##{id} factbase at #{@host}"
|
164
137
|
end
|
@@ -176,15 +149,7 @@ class BazaRb
|
|
176
149
|
raise 'The ID of the job must be a positive integer' unless id.positive?
|
177
150
|
fin = false
|
178
151
|
elapsed(@loog) do
|
179
|
-
ret =
|
180
|
-
retry_it do
|
181
|
-
checked(
|
182
|
-
Typhoeus::Request.get(
|
183
|
-
home.append('finished').append(id).to_s,
|
184
|
-
headers:
|
185
|
-
)
|
186
|
-
)
|
187
|
-
end
|
152
|
+
ret = get(home.append('finished').append(id))
|
188
153
|
fin = ret.body == 'yes'
|
189
154
|
throw :"The job ##{id} is #{'not yet ' unless fin}finished at #{@host}#{" (#{ret.body.inspect})" unless fin}"
|
190
155
|
end
|
@@ -195,20 +160,13 @@ class BazaRb
|
|
195
160
|
#
|
196
161
|
# @param [Integer] id The ID of the job on the server
|
197
162
|
# @return [String] The stdout, as a text
|
163
|
+
# @raise [ServerFailure] If the job doesn't exist or retrieval fails
|
198
164
|
def stdout(id)
|
199
165
|
raise 'The ID of the job is nil' if id.nil?
|
200
166
|
raise 'The ID of the job must be a positive integer' unless id.positive?
|
201
167
|
stdout = ''
|
202
168
|
elapsed(@loog) do
|
203
|
-
ret =
|
204
|
-
retry_it do
|
205
|
-
checked(
|
206
|
-
Typhoeus::Request.get(
|
207
|
-
home.append('stdout').append("#{id}.txt").to_s,
|
208
|
-
headers:
|
209
|
-
)
|
210
|
-
)
|
211
|
-
end
|
169
|
+
ret = get(home.append('stdout').append("#{id}.txt"))
|
212
170
|
stdout = ret.body
|
213
171
|
throw :"The stdout of the job ##{id} has #{stdout.split("\n").count} lines"
|
214
172
|
end
|
@@ -219,20 +177,13 @@ class BazaRb
|
|
219
177
|
#
|
220
178
|
# @param [Integer] id The ID of the job on the server
|
221
179
|
# @return [Integer] The exit code
|
180
|
+
# @raise [ServerFailure] If the job doesn't exist or retrieval fails
|
222
181
|
def exit_code(id)
|
223
182
|
raise 'The ID of the job is nil' if id.nil?
|
224
183
|
raise 'The ID of the job must be a positive integer' unless id.positive?
|
225
184
|
code = 0
|
226
185
|
elapsed(@loog) do
|
227
|
-
ret =
|
228
|
-
retry_it do
|
229
|
-
checked(
|
230
|
-
Typhoeus::Request.get(
|
231
|
-
home.append('exit').append("#{id}.txt").to_s,
|
232
|
-
headers:
|
233
|
-
)
|
234
|
-
)
|
235
|
-
end
|
186
|
+
ret = get(home.append('exit').append("#{id}.txt"))
|
236
187
|
code = ret.body.to_i
|
237
188
|
throw :"The exit code of the job ##{id} is #{code}"
|
238
189
|
end
|
@@ -243,20 +194,13 @@ class BazaRb
|
|
243
194
|
#
|
244
195
|
# @param [Integer] id The ID of the job on the server
|
245
196
|
# @return [String] The verdict
|
197
|
+
# @raise [ServerFailure] If the job doesn't exist or retrieval fails
|
246
198
|
def verified(id)
|
247
199
|
raise 'The ID of the job is nil' if id.nil?
|
248
200
|
raise 'The ID of the job must be a positive integer' unless id.positive?
|
249
201
|
verdict = ''
|
250
202
|
elapsed(@loog) do
|
251
|
-
ret =
|
252
|
-
retry_it do
|
253
|
-
checked(
|
254
|
-
Typhoeus::Request.get(
|
255
|
-
home.append('jobs').append(id).append('verified.txt').to_s,
|
256
|
-
headers:
|
257
|
-
)
|
258
|
-
)
|
259
|
-
end
|
203
|
+
ret = get(home.append('jobs').append(id).append('verified.txt'))
|
260
204
|
verdict = ret.body
|
261
205
|
throw :"The verdict of the job ##{id} is #{verdict.inspect}"
|
262
206
|
end
|
@@ -267,21 +211,18 @@ class BazaRb
|
|
267
211
|
#
|
268
212
|
# @param [String] name The name of the job on the server
|
269
213
|
# @param [String] owner The owner of the lock (any string)
|
214
|
+
# @raise [RuntimeError] If the name is already locked
|
215
|
+
# @raise [ServerFailure] If the lock operation fails
|
270
216
|
def lock(name, owner)
|
271
217
|
raise 'The "name" of the job is nil' if name.nil?
|
272
218
|
raise 'The "name" of the job may not be empty' if name.empty?
|
273
219
|
raise 'The "owner" of the lock is nil' if owner.nil?
|
274
220
|
elapsed(@loog) do
|
275
|
-
ret =
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
headers:
|
281
|
-
),
|
282
|
-
[302, 409]
|
283
|
-
)
|
284
|
-
end
|
221
|
+
ret = post(
|
222
|
+
home.append('lock').append(name),
|
223
|
+
{ 'owner' => owner },
|
224
|
+
[302, 409]
|
225
|
+
)
|
285
226
|
throw :"Job name '#{name}' locked at #{@host}" if ret.code == 302
|
286
227
|
raise "Failed to lock '#{name}' job at #{@host}, it's already locked"
|
287
228
|
end
|
@@ -291,21 +232,17 @@ class BazaRb
|
|
291
232
|
#
|
292
233
|
# @param [String] name The name of the job on the server
|
293
234
|
# @param [String] owner The owner of the lock (any string)
|
235
|
+
# @raise [ServerFailure] If the unlock operation fails
|
294
236
|
def unlock(name, owner)
|
295
237
|
raise 'The "name" of the job is nil' if name.nil?
|
296
238
|
raise 'The "name" of the job may not be empty' if name.empty?
|
297
239
|
raise 'The "owner" of the lock is nil' if owner.nil?
|
298
240
|
raise 'The "owner" of the lock may not be empty' if owner.empty?
|
299
241
|
elapsed(@loog) do
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
headers:
|
305
|
-
),
|
306
|
-
302
|
307
|
-
)
|
308
|
-
end
|
242
|
+
post(
|
243
|
+
home.append('unlock').append(name),
|
244
|
+
{ 'owner' => owner }
|
245
|
+
)
|
309
246
|
throw :"Job name '#{name}' unlocked at #{@host}"
|
310
247
|
end
|
311
248
|
end
|
@@ -314,20 +251,13 @@ class BazaRb
|
|
314
251
|
#
|
315
252
|
# @param [String] name The name of the job on the server
|
316
253
|
# @return [Integer] The ID of the job on the server
|
254
|
+
# @raise [ServerFailure] If the job doesn't exist or retrieval fails
|
317
255
|
def recent(name)
|
318
256
|
raise 'The "name" of the job is nil' if name.nil?
|
319
257
|
raise 'The "name" of the job may not be empty' if name.empty?
|
320
258
|
job = nil
|
321
259
|
elapsed(@loog) do
|
322
|
-
ret =
|
323
|
-
retry_it do
|
324
|
-
checked(
|
325
|
-
Typhoeus::Request.get(
|
326
|
-
home.append('recent').append("#{name}.txt").to_s,
|
327
|
-
headers:
|
328
|
-
)
|
329
|
-
)
|
330
|
-
end
|
260
|
+
ret = get(home.append('recent').append("#{name}.txt"))
|
331
261
|
job = ret.body.to_i
|
332
262
|
throw :"The recent \"#{name}\" job's ID is ##{job} at #{@host}"
|
333
263
|
end
|
@@ -343,15 +273,7 @@ class BazaRb
|
|
343
273
|
raise 'The "name" of the job may not be empty' if name.empty?
|
344
274
|
exists = false
|
345
275
|
elapsed(@loog) do
|
346
|
-
ret =
|
347
|
-
retry_it do
|
348
|
-
checked(
|
349
|
-
Typhoeus::Request.get(
|
350
|
-
home.append('exists').append(name).to_s,
|
351
|
-
headers:
|
352
|
-
)
|
353
|
-
)
|
354
|
-
end
|
276
|
+
ret = get(home.append('exists').append(name))
|
355
277
|
exists = ret.body == 'yes'
|
356
278
|
throw :"The name \"#{name}\" #{exists ? 'exists' : "doesn't exist"} at #{@host}"
|
357
279
|
end
|
@@ -362,9 +284,10 @@ class BazaRb
|
|
362
284
|
#
|
363
285
|
# @param [String] jname The name of the job on the server
|
364
286
|
# @param [String] file The path to the file to upload
|
287
|
+
# @param [Integer] chunk_size Maximum size of one chunk
|
365
288
|
# @return [Integer] The ID of the created durable
|
366
289
|
# @raise [ServerFailure] If the upload fails
|
367
|
-
def durable_place(jname, file)
|
290
|
+
def durable_place(jname, file, chunk_size: 1_000_000)
|
368
291
|
raise 'The "jname" of the durable is nil' if jname.nil?
|
369
292
|
raise 'The "jname" of the durable may not be empty' if jname.empty?
|
370
293
|
raise 'The "file" of the durable is nil' if file.nil?
|
@@ -373,30 +296,20 @@ class BazaRb
|
|
373
296
|
Tempfile.open do |f|
|
374
297
|
File.write(f.path, 'placeholder')
|
375
298
|
elapsed(@loog) do
|
376
|
-
ret =
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
'file' => File.basename(file),
|
385
|
-
'zip' => File.open(f, 'rb')
|
386
|
-
},
|
387
|
-
headers:,
|
388
|
-
connecttimeout: @timeout,
|
389
|
-
timeout: @timeout
|
390
|
-
),
|
391
|
-
302
|
392
|
-
)
|
393
|
-
end
|
299
|
+
ret = post(
|
300
|
+
home.append('durables').append('place'),
|
301
|
+
{
|
302
|
+
'jname' => jname,
|
303
|
+
'file' => File.basename(file),
|
304
|
+
'zip' => File.open(f, 'rb')
|
305
|
+
}
|
306
|
+
)
|
394
307
|
id = ret.headers['X-Zerocracy-DurableId'].to_i
|
395
|
-
throw :"Durable ##{id} (#{file}) placed for job \"#{jname}\" at #{@host}"
|
308
|
+
throw :"Durable ##{id} (#{file}, #{File.size(file)} bytes) placed for job \"#{jname}\" at #{@host}"
|
396
309
|
end
|
397
310
|
end
|
398
311
|
durable_lock(id, user_agent)
|
399
|
-
durable_save(id, file)
|
312
|
+
durable_save(id, file, chunk_size:)
|
400
313
|
durable_unlock(id, user_agent)
|
401
314
|
id
|
402
315
|
end
|
@@ -405,23 +318,15 @@ class BazaRb
|
|
405
318
|
#
|
406
319
|
# @param [Integer] id The ID of the durable
|
407
320
|
# @param [String] file The file to upload
|
408
|
-
|
321
|
+
# @param [Integer] chunk_size Maximum size of one chunk
|
322
|
+
# @raise [ServerFailure] If the save operation fails
|
323
|
+
def durable_save(id, file, chunk_size: 1_000_000)
|
409
324
|
raise 'The ID of the durable is nil' if id.nil?
|
410
325
|
raise 'The ID of the durable must be a positive integer' unless id.positive?
|
411
326
|
raise 'The "file" of the durable is nil' if file.nil?
|
412
327
|
raise "The file '#{file}' is absent" unless File.exist?(file)
|
413
328
|
elapsed(@loog) do
|
414
|
-
|
415
|
-
checked(
|
416
|
-
Typhoeus::Request.put(
|
417
|
-
home.append('durables').append(id).to_s,
|
418
|
-
body: File.binread(file),
|
419
|
-
headers:,
|
420
|
-
connecttimeout: @timeout,
|
421
|
-
timeout: @timeout
|
422
|
-
)
|
423
|
-
)
|
424
|
-
end
|
329
|
+
upload(home.append('durables').append(id), file, chunk_size:)
|
425
330
|
throw :"Durable ##{id} saved #{File.size(file)} bytes to #{@host}"
|
426
331
|
end
|
427
332
|
end
|
@@ -429,13 +334,14 @@ class BazaRb
|
|
429
334
|
# Load a single durable from server to local file.
|
430
335
|
#
|
431
336
|
# @param [Integer] id The ID of the durable
|
432
|
-
# @param [String] file The file to
|
337
|
+
# @param [String] file The local file path to save the downloaded durable
|
338
|
+
# @raise [ServerFailure] If the load operation fails
|
433
339
|
def durable_load(id, file)
|
434
340
|
raise 'The ID of the durable is nil' if id.nil?
|
435
341
|
raise 'The ID of the durable must be a positive integer' unless id.positive?
|
436
342
|
raise 'The "file" of the durable is nil' if file.nil?
|
437
343
|
elapsed(@loog) do
|
438
|
-
download(home.append('durables').append(id)
|
344
|
+
download(home.append('durables').append(id), file)
|
439
345
|
throw :"Durable ##{id} loaded #{File.size(file)} bytes from #{@host}"
|
440
346
|
end
|
441
347
|
end
|
@@ -444,21 +350,17 @@ class BazaRb
|
|
444
350
|
#
|
445
351
|
# @param [Integer] id The ID of the durable
|
446
352
|
# @param [String] owner The owner of the lock
|
353
|
+
# @raise [ServerFailure] If the lock operation fails
|
447
354
|
def durable_lock(id, owner)
|
448
355
|
raise 'The ID of the durable is nil' if id.nil?
|
449
356
|
raise 'The ID of the durable must be a positive integer' unless id.positive?
|
450
357
|
raise 'The "owner" of the lock is nil' if owner.nil?
|
451
358
|
raise 'The "owner" of the lock may not be empty' if owner.empty?
|
452
359
|
elapsed(@loog) do
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
headers:
|
458
|
-
),
|
459
|
-
302
|
460
|
-
)
|
461
|
-
end
|
360
|
+
post(
|
361
|
+
home.append('durables').append(id).append('lock'),
|
362
|
+
{ 'owner' => owner }
|
363
|
+
)
|
462
364
|
throw :"Durable ##{id} locked at #{@host}"
|
463
365
|
end
|
464
366
|
end
|
@@ -467,21 +369,17 @@ class BazaRb
|
|
467
369
|
#
|
468
370
|
# @param [Integer] id The ID of the durable
|
469
371
|
# @param [String] owner The owner of the lock
|
372
|
+
# @raise [ServerFailure] If the unlock operation fails
|
470
373
|
def durable_unlock(id, owner)
|
471
374
|
raise 'The ID of the durable is nil' if id.nil?
|
472
375
|
raise 'The ID of the durable must be a positive integer' unless id.positive?
|
473
376
|
raise 'The "owner" of the lock is nil' if owner.nil?
|
474
377
|
raise 'The "owner" of the lock may not be empty' if owner.empty?
|
475
378
|
elapsed(@loog) do
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
headers:
|
481
|
-
),
|
482
|
-
302
|
483
|
-
)
|
484
|
-
end
|
379
|
+
post(
|
380
|
+
home.append('durables').append(id).append('unlock'),
|
381
|
+
{ 'owner' => owner }
|
382
|
+
)
|
485
383
|
throw :"Durable ##{id} unlocked at #{@host}"
|
486
384
|
end
|
487
385
|
end
|
@@ -498,16 +396,7 @@ class BazaRb
|
|
498
396
|
raise 'The "file" may not be empty' if file.empty?
|
499
397
|
id = nil
|
500
398
|
elapsed(@loog) do
|
501
|
-
ret =
|
502
|
-
retry_it do
|
503
|
-
checked(
|
504
|
-
Typhoeus::Request.get(
|
505
|
-
home.append('durables').append('find').add(jname:, file:).to_s,
|
506
|
-
headers:
|
507
|
-
),
|
508
|
-
[200, 404]
|
509
|
-
)
|
510
|
-
end
|
399
|
+
ret = get(home.append('durables').append('find').add(jname:, file:), [200, 404])
|
511
400
|
if ret.code == 200
|
512
401
|
id = ret.body.to_i
|
513
402
|
throw :"Found durable ##{id} for job \"#{jname}\" file \"#{file}\" at #{@host}"
|
@@ -533,26 +422,16 @@ class BazaRb
|
|
533
422
|
raise 'The "summary" is nil' if summary.nil?
|
534
423
|
id = nil
|
535
424
|
body = {
|
536
|
-
'_csrf' => csrf,
|
537
425
|
'human' => recipient,
|
538
426
|
'amount' => format('%0.6f', amount),
|
539
427
|
'summary' => summary
|
540
428
|
}
|
541
429
|
body['job'] = job unless job.nil?
|
542
430
|
elapsed(@loog) do
|
543
|
-
ret =
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
home.append('account').append('transfer').to_s,
|
548
|
-
body:,
|
549
|
-
headers:,
|
550
|
-
connecttimeout: @timeout,
|
551
|
-
timeout: @timeout
|
552
|
-
),
|
553
|
-
302
|
554
|
-
)
|
555
|
-
end
|
431
|
+
ret = post(
|
432
|
+
home.append('account').append('transfer'),
|
433
|
+
body
|
434
|
+
)
|
556
435
|
id = ret.headers['X-Zerocracy-ReceiptId'].to_i
|
557
436
|
throw :"Transferred Ƶ#{format('%0.6f', amount)} to @#{recipient} at #{@host}"
|
558
437
|
end
|
@@ -575,27 +454,16 @@ class BazaRb
|
|
575
454
|
raise 'The "job" must be Integer' unless job.is_a?(Integer)
|
576
455
|
raise 'The "summary" is nil' if summary.nil?
|
577
456
|
id = nil
|
578
|
-
body = {
|
579
|
-
'_csrf' => csrf,
|
580
|
-
'tab' => tab,
|
581
|
-
'amount' => format('%0.6f', amount),
|
582
|
-
'summary' => summary,
|
583
|
-
'job' => job.to_s
|
584
|
-
}
|
585
457
|
elapsed(@loog) do
|
586
|
-
ret =
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
),
|
596
|
-
302
|
597
|
-
)
|
598
|
-
end
|
458
|
+
ret = post(
|
459
|
+
home.append('account').append('fee'),
|
460
|
+
{
|
461
|
+
'tab' => tab,
|
462
|
+
'amount' => format('%0.6f', amount),
|
463
|
+
'summary' => summary,
|
464
|
+
'job' => job.to_s
|
465
|
+
}
|
466
|
+
)
|
599
467
|
id = ret.headers['X-Zerocracy-ReceiptId'].to_i
|
600
468
|
throw :"Fee Ƶ#{format('%0.6f', amount)} paid at #{@host}"
|
601
469
|
end
|
@@ -612,16 +480,7 @@ class BazaRb
|
|
612
480
|
success = false
|
613
481
|
elapsed(@loog) do
|
614
482
|
uri = home.append('pop').add(owner:)
|
615
|
-
ret =
|
616
|
-
retry_it do
|
617
|
-
checked(
|
618
|
-
Typhoeus::Request.get(
|
619
|
-
uri.to_s,
|
620
|
-
headers:
|
621
|
-
),
|
622
|
-
[204, 302]
|
623
|
-
)
|
624
|
-
end
|
483
|
+
ret = get(uri, [204, 302])
|
625
484
|
if ret.code == 204
|
626
485
|
FileUtils.rm_f(zip)
|
627
486
|
throw :"Nothing to pop at #{uri}"
|
@@ -647,20 +506,7 @@ class BazaRb
|
|
647
506
|
raise 'The "zip" of the job is nil' if zip.nil?
|
648
507
|
raise "The 'zip' file is absent: #{zip}" unless File.exist?(zip)
|
649
508
|
elapsed(@loog) do
|
650
|
-
|
651
|
-
checked(
|
652
|
-
Typhoeus::Request.put(
|
653
|
-
home.append('finish').add(id:).to_s,
|
654
|
-
connecttimeout: @timeout,
|
655
|
-
timeout: @timeout,
|
656
|
-
body: File.binread(zip),
|
657
|
-
headers: headers.merge(
|
658
|
-
'Content-Type' => 'application/octet-stream',
|
659
|
-
'Content-Length' => File.size(zip)
|
660
|
-
)
|
661
|
-
)
|
662
|
-
)
|
663
|
-
end
|
509
|
+
upload(home.append('finish').add(id:), zip)
|
664
510
|
throw :"Pushed #{File.size(zip)} bytes to #{@host}, finished job ##{id}"
|
665
511
|
end
|
666
512
|
end
|
@@ -681,30 +527,19 @@ class BazaRb
|
|
681
527
|
def enter(name, badge, why, job)
|
682
528
|
elapsed(@loog, intro: "Entered valve #{badge} to #{name}") do
|
683
529
|
retry_it do
|
684
|
-
ret =
|
685
|
-
Typhoeus::Request.get(
|
686
|
-
home.append('valves').append('result').add(badge:).to_s,
|
687
|
-
headers:
|
688
|
-
),
|
689
|
-
[200, 204]
|
690
|
-
)
|
530
|
+
ret = get(home.append('valves').append('result').add(badge:), [200, 204])
|
691
531
|
return ret.body if ret.code == 200
|
692
532
|
r = yield
|
693
533
|
uri = home.append('valves').append('add')
|
694
534
|
uri = uri.add(job:) unless job.nil?
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
'result' => r.to_s
|
704
|
-
},
|
705
|
-
headers:
|
706
|
-
),
|
707
|
-
302
|
535
|
+
post(
|
536
|
+
uri,
|
537
|
+
{
|
538
|
+
'name' => name,
|
539
|
+
'badge' => badge,
|
540
|
+
'why' => why,
|
541
|
+
'result' => r.to_s
|
542
|
+
}
|
708
543
|
)
|
709
544
|
r
|
710
545
|
end
|
@@ -721,15 +556,7 @@ class BazaRb
|
|
721
556
|
def csrf
|
722
557
|
token = nil
|
723
558
|
elapsed(@loog) do
|
724
|
-
|
725
|
-
token = checked(
|
726
|
-
Typhoeus::Request.get(
|
727
|
-
home.append('csrf').to_s,
|
728
|
-
headers:
|
729
|
-
),
|
730
|
-
200
|
731
|
-
).body
|
732
|
-
end
|
559
|
+
token = get(home.append('csrf')).body
|
733
560
|
throw :"CSRF token retrieved (#{token.length} chars)"
|
734
561
|
end
|
735
562
|
token
|
@@ -737,10 +564,16 @@ class BazaRb
|
|
737
564
|
|
738
565
|
private
|
739
566
|
|
567
|
+
# Get the user agent string for HTTP requests.
|
568
|
+
#
|
569
|
+
# @return [String] The user agent string
|
740
570
|
def user_agent
|
741
571
|
"baza.rb #{BazaRb::VERSION}"
|
742
572
|
end
|
743
573
|
|
574
|
+
# Get default headers for HTTP requests.
|
575
|
+
#
|
576
|
+
# @return [Hash] The default headers including User-Agent, Connection, and authentication token
|
744
577
|
def headers
|
745
578
|
{
|
746
579
|
'User-Agent' => user_agent,
|
@@ -749,8 +582,28 @@ class BazaRb
|
|
749
582
|
}
|
750
583
|
end
|
751
584
|
|
585
|
+
# Decompress gzipped data.
|
586
|
+
#
|
587
|
+
# @param [String] data The gzipped data to decompress
|
588
|
+
# @return [String] The decompressed data
|
589
|
+
def unzip(data)
|
590
|
+
io = StringIO.new(data)
|
591
|
+
gz = Zlib::GzipReader.new(io)
|
592
|
+
gz.read
|
593
|
+
rescue Zlib::GzipFile::Error => e
|
594
|
+
raise BadCompression, "Failed to unzip #{data.bytesize} bytes: #{e.message}"
|
595
|
+
end
|
596
|
+
|
597
|
+
# Compress request parameters with gzip.
|
598
|
+
#
|
599
|
+
# @param [Hash] params The request parameters with :body and :headers keys
|
600
|
+
# @return [Hash] The modified parameters with compressed body and updated headers
|
752
601
|
def zipped(params)
|
753
|
-
|
602
|
+
io = StringIO.new
|
603
|
+
gz = Zlib::GzipWriter.new(io)
|
604
|
+
gz.write(params.fetch(:body))
|
605
|
+
gz.close
|
606
|
+
body = io.string
|
754
607
|
headers = params
|
755
608
|
.fetch(:headers)
|
756
609
|
.merge(
|
@@ -763,15 +616,9 @@ class BazaRb
|
|
763
616
|
params.merge(body:, headers:)
|
764
617
|
end
|
765
618
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
gz = Zlib::GzipWriter.new(io)
|
770
|
-
gz.write(data)
|
771
|
-
gz.close
|
772
|
-
end
|
773
|
-
end
|
774
|
-
|
619
|
+
# Build the base URI for API requests.
|
620
|
+
#
|
621
|
+
# @return [Iri] The base URI object
|
775
622
|
def home
|
776
623
|
Iri.new('')
|
777
624
|
.host(@host)
|
@@ -779,6 +626,10 @@ class BazaRb
|
|
779
626
|
.scheme(@ssl ? 'https' : 'http')
|
780
627
|
end
|
781
628
|
|
629
|
+
# Execute a block with retries on timeout.
|
630
|
+
#
|
631
|
+
# @yield The block to execute with retries
|
632
|
+
# @return [Object] The result of the block execution
|
782
633
|
def retry_it(&)
|
783
634
|
with_retries(max_tries: @retries, rescue: TimedOut, &)
|
784
635
|
end
|
@@ -831,89 +682,173 @@ class BazaRb
|
|
831
682
|
raise ServerFailure, msg
|
832
683
|
end
|
833
684
|
|
834
|
-
#
|
835
|
-
#
|
836
|
-
# @param [
|
685
|
+
# Make a GET request.
|
686
|
+
#
|
687
|
+
# @param [Iri] uri The URI to send the request to
|
688
|
+
# @param [Array<Integer>] allowed List of allowed HTTP response codes
|
689
|
+
# @return [Typhoeus::Response] The HTTP response
|
690
|
+
# @raise [ServerFailure] If the response code is not in the allowed list
|
691
|
+
def get(uri, allowed = [200])
|
692
|
+
retry_it do
|
693
|
+
checked(
|
694
|
+
Typhoeus::Request.get(
|
695
|
+
uri.to_s,
|
696
|
+
headers:,
|
697
|
+
connecttimeout: @timeout,
|
698
|
+
timeout: @timeout
|
699
|
+
),
|
700
|
+
allowed
|
701
|
+
)
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
# Make a POST request.
|
706
|
+
#
|
707
|
+
# @param [Iri] uri The URI to send the request to
|
708
|
+
# @param [Hash] params The request parameters to send in the body
|
709
|
+
# @param [Array<Integer>] allowed List of allowed HTTP response codes
|
710
|
+
# @return [Typhoeus::Response] The HTTP response
|
711
|
+
# @raise [ServerFailure] If the response code is not in the allowed list
|
712
|
+
def post(uri, params, allowed = [302])
|
713
|
+
retry_it do
|
714
|
+
checked(
|
715
|
+
Typhoeus::Request.post(
|
716
|
+
uri.to_s,
|
717
|
+
body: params.merge('_csrf' => csrf),
|
718
|
+
headers:,
|
719
|
+
connecttimeout: @timeout,
|
720
|
+
timeout: @timeout
|
721
|
+
),
|
722
|
+
allowed
|
723
|
+
)
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
# Download file via GET, using range requests for large files.
|
728
|
+
#
|
729
|
+
# @param [Iri] uri The URI to download from
|
730
|
+
# @param [String] file The local file path to save to
|
731
|
+
# @raise [ServerFailure] If the download fails
|
837
732
|
def download(uri, file)
|
838
|
-
raise 'The "file" is nil' if file.nil?
|
839
733
|
FileUtils.mkdir_p(File.dirname(file))
|
734
|
+
FileUtils.rm_f(file)
|
735
|
+
chunk = 0
|
840
736
|
elapsed(@loog) do
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
737
|
+
pos = 0
|
738
|
+
loop do
|
739
|
+
request = Typhoeus::Request.new(
|
740
|
+
uri.to_s,
|
741
|
+
method: :get,
|
742
|
+
headers: headers.merge(
|
743
|
+
'Accept' => 'application/octet-stream',
|
744
|
+
'Accept-Encoding' => 'gzip',
|
745
|
+
'Range' => "bytes=#{pos}-"
|
746
|
+
),
|
747
|
+
connecttimeout: @timeout,
|
748
|
+
timeout: @timeout
|
749
|
+
)
|
750
|
+
slice = ''
|
751
|
+
request.on_body do |data|
|
752
|
+
slice = data
|
753
|
+
end
|
754
|
+
retry_it do
|
755
|
+
request.run
|
756
|
+
end
|
757
|
+
ret = request.response
|
758
|
+
msg = [
|
759
|
+
"GET #{uri.to_uri.path} #{ret.code}",
|
760
|
+
"#{slice.bytesize} bytes",
|
761
|
+
('in gzip' if ret.headers['Content-Encoding'] == 'gzip'),
|
762
|
+
("ranged as #{ret.headers['Content-Range'].inspect}" if ret.headers['Content-Range'])
|
763
|
+
]
|
764
|
+
ret = checked(ret, [200, 206])
|
765
|
+
if ret.headers['Content-Encoding'] == 'gzip'
|
766
|
+
begin
|
767
|
+
slice = unzip(slice)
|
768
|
+
msg << "unzipped to #{slice.bytesize} bytes"
|
769
|
+
rescue BazaRb::BadCompression => e
|
770
|
+
raise BazaRb::BadCompression, "#{msg.compact.join(', ')} (#{e.message})"
|
871
771
|
end
|
872
|
-
break if e.to_i == total.to_i - 1
|
873
772
|
end
|
773
|
+
File.open(file, 'ab') do |f|
|
774
|
+
msg << "added to existed #{File.size(file)} bytes"
|
775
|
+
f.write(slice)
|
776
|
+
end
|
777
|
+
@loog.debug(msg.compact.join(', '))
|
778
|
+
break if ret.code == 200
|
779
|
+
_, v = ret.headers['Content-Range'].split
|
780
|
+
range, total = v.split('/')
|
781
|
+
raise "Total size is not valid (#{total.inspect})" unless total.match?(/^\*|[0-9]+$/)
|
782
|
+
_b, e = range.split('-')
|
783
|
+
raise "Range is not valid (#{range.inspect})" unless e.match?(/^[0-9]+$/)
|
784
|
+
len = ret.headers['Content-Length'].to_i
|
785
|
+
pos = e.to_i
|
786
|
+
pos += 1 unless len.zero?
|
787
|
+
break if e.to_i == total.to_i - 1
|
788
|
+
chunk += 1
|
789
|
+
sleep(1) if len.zero?
|
874
790
|
end
|
875
|
-
throw :"Downloaded #{File.size(file)} bytes from #{uri}"
|
791
|
+
throw :"Downloaded #{File.size(file)} bytes in #{chunk + 1} chunks from #{uri}"
|
876
792
|
end
|
877
793
|
end
|
878
794
|
|
879
|
-
# Upload file via PUT,
|
880
|
-
#
|
881
|
-
# @param [
|
882
|
-
# @param [
|
883
|
-
|
884
|
-
|
885
|
-
|
795
|
+
# Upload file via PUT, using chunked uploads for large files.
|
796
|
+
#
|
797
|
+
# @param [Iri] uri The URI to upload to
|
798
|
+
# @param [String] file The local file path to upload from
|
799
|
+
# @param [Hash] extra Hash of extra HTTP headers to include
|
800
|
+
# @param [Integer] chunk_size Maximum size of each chunk in bytes
|
801
|
+
# @raise [ServerFailure] If the upload fails
|
802
|
+
def upload(uri, file, extra = {}, chunk_size: 1_000_000)
|
886
803
|
params = {
|
887
804
|
connecttimeout: @timeout,
|
888
805
|
timeout: @timeout,
|
889
|
-
|
890
|
-
headers: headers.merge(
|
806
|
+
headers: headers.merge(extra).merge(
|
891
807
|
'Content-Type' => 'application/octet-stream'
|
892
808
|
)
|
893
809
|
}
|
894
|
-
|
810
|
+
total = File.size(file)
|
895
811
|
chunk = 0
|
812
|
+
sent = 0
|
896
813
|
elapsed(@loog) do
|
897
|
-
params[:headers]['X-Zerocracy-Chunk'] = chunk.to_s
|
898
814
|
loop do
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
815
|
+
slice =
|
816
|
+
if total > chunk_size
|
817
|
+
File.open(file, 'rb') do |f|
|
818
|
+
params[:headers]['X-Zerocracy-Chunk'] = chunk.to_s
|
819
|
+
f.seek(chunk_size * chunk)
|
820
|
+
f.read(chunk_size) || ''
|
821
|
+
end
|
822
|
+
else
|
823
|
+
File.binread(file)
|
824
|
+
end
|
825
|
+
params[:body] = slice
|
826
|
+
params[:headers]['Content-Length'] = slice.bytesize
|
827
|
+
params = zipped(params) if @compress
|
828
|
+
ret =
|
904
829
|
retry_it do
|
905
830
|
checked(
|
906
831
|
Typhoeus::Request.put(
|
907
832
|
uri.to_s,
|
908
|
-
|
833
|
+
params
|
909
834
|
)
|
910
835
|
)
|
911
836
|
end
|
912
|
-
|
913
|
-
|
837
|
+
sent += params[:body].bytesize
|
838
|
+
@loog.debug(
|
839
|
+
[
|
840
|
+
"PUT #{uri.to_uri.path} #{ret.code}",
|
841
|
+
("gzipped #{slice.bytesize} bytes" if params[:headers]['Content-Encoding'] == 'gzip'),
|
842
|
+
"sent #{params[:body].bytesize} bytes",
|
843
|
+
("chunk ##{chunk}" if params[:headers]['X-Zerocracy-Chunk']),
|
844
|
+
('no chunks' unless params[:headers]['X-Zerocracy-Chunk'])
|
845
|
+
].compact.join(', ')
|
846
|
+
)
|
847
|
+
break if slice.empty?
|
848
|
+
break if total <= chunk_size
|
914
849
|
chunk += 1
|
915
850
|
end
|
916
|
-
throw :"Uploaded #{
|
851
|
+
throw :"Uploaded #{sent} bytes to #{uri}#{" in #{chunk + 1} chunks" if chunk.positive?}"
|
917
852
|
end
|
918
853
|
end
|
919
854
|
end
|
data/test/test_baza-rb.rb
CHANGED
@@ -40,7 +40,7 @@ class TestBazaRb < Minitest::Test
|
|
40
40
|
fb.insert.foo = 'test-' * 10_000
|
41
41
|
fb.insert
|
42
42
|
n = fake_name
|
43
|
-
|
43
|
+
LIVE.push(n, fb.export, [])
|
44
44
|
assert(LIVE.name_exists?(n))
|
45
45
|
assert_predicate(LIVE.recent(n), :positive?)
|
46
46
|
id = LIVE.recent(n)
|
@@ -86,15 +86,16 @@ class TestBazaRb < Minitest::Test
|
|
86
86
|
fb.insert.foo = 'test-' * 10_000
|
87
87
|
fb.insert
|
88
88
|
baza = BazaRb.new(HOST, PORT, TOKEN, compress: false)
|
89
|
-
|
89
|
+
baza.push(fake_name, fb.export, [])
|
90
90
|
end
|
91
91
|
|
92
92
|
def test_live_durable_lock_unlock
|
93
93
|
WebMock.enable_net_connect!
|
94
94
|
skip('We are offline') unless we_are_online
|
95
95
|
Dir.mktmpdir do |dir|
|
96
|
-
file = File.join(dir,
|
97
|
-
|
96
|
+
file = File.join(dir, 'before.bin')
|
97
|
+
before = 'hello, Джеф!' * 10
|
98
|
+
File.binwrite(file, before)
|
98
99
|
jname = fake_name
|
99
100
|
refute(LIVE.durable_find(jname, File.basename(file)))
|
100
101
|
id = LIVE.durable_place(jname, file)
|
@@ -102,7 +103,12 @@ class TestBazaRb < Minitest::Test
|
|
102
103
|
owner = fake_name
|
103
104
|
LIVE.durable_lock(id, owner)
|
104
105
|
LIVE.durable_load(id, file)
|
106
|
+
assert_equal(before, File.binread(file).force_encoding('UTF-8'))
|
107
|
+
after = 'привет, друг!'
|
108
|
+
File.binwrite(file, after)
|
105
109
|
LIVE.durable_save(id, file)
|
110
|
+
LIVE.durable_load(id, file)
|
111
|
+
assert_equal(after, File.binread(file).force_encoding('UTF-8'))
|
106
112
|
LIVE.durable_unlock(id, owner)
|
107
113
|
end
|
108
114
|
end
|
@@ -169,25 +175,36 @@ class TestBazaRb < Minitest::Test
|
|
169
175
|
|
170
176
|
def test_unlocks_job_by_name
|
171
177
|
WebMock.disable_net_connect!
|
172
|
-
stub_request(:get, 'https://example.org/
|
178
|
+
stub_request(:get, 'https://example.org/csrf').to_return(body: 'token')
|
179
|
+
stub_request(:post, %r{https://example.org/unlock/foo}).to_return(status: 302)
|
173
180
|
assert(fake_baza.unlock('foo', 'x'))
|
174
181
|
end
|
175
182
|
|
176
183
|
def test_durable_place
|
177
184
|
WebMock.disable_net_connect!
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
185
|
+
[fake_baza(compress: true), fake_baza(compress: false)].each do |baza|
|
186
|
+
stub_request(:get, 'https://example.org/csrf').to_return(body: 'token')
|
187
|
+
stub_request(:post, 'https://example.org/durables/place').to_return(
|
188
|
+
status: 302, headers: { 'X-Zerocracy-DurableId' => '42' }
|
189
|
+
)
|
190
|
+
stub_request(:post, %r{https://example\.org/durables/42/lock})
|
191
|
+
.to_return(status: 302)
|
192
|
+
stub_request(:post, %r{https://example\.org/durables/42/unlock})
|
193
|
+
.to_return(status: 302)
|
194
|
+
stub_request(:put, 'https://example.org/durables/42')
|
195
|
+
.with(headers: { 'X-Zerocracy-Chunk' => '0' })
|
196
|
+
.to_return(status: 200)
|
197
|
+
stub_request(:put, 'https://example.org/durables/42')
|
198
|
+
.with(headers: { 'X-Zerocracy-Chunk' => '1' })
|
199
|
+
.to_return(status: 200)
|
200
|
+
stub_request(:put, 'https://example.org/durables/42')
|
201
|
+
.with(headers: { 'X-Zerocracy-Chunk' => '2' })
|
202
|
+
.to_return(status: 200)
|
203
|
+
Dir.mktmpdir do |dir|
|
204
|
+
file = File.join(dir, 'test.bin')
|
205
|
+
File.binwrite(file, 'hello, world!')
|
206
|
+
assert_equal(42, baza.durable_place('simple', file, chunk_size: 8))
|
207
|
+
end
|
191
208
|
end
|
192
209
|
end
|
193
210
|
|
@@ -196,10 +213,7 @@ class TestBazaRb < Minitest::Test
|
|
196
213
|
stub_request(:put, 'https://example.org/push/simple').to_return(
|
197
214
|
status: 200, body: '42'
|
198
215
|
)
|
199
|
-
|
200
|
-
42,
|
201
|
-
fake_baza.push('simple', 'hello, world!', [])
|
202
|
-
)
|
216
|
+
fake_baza.push('simple', 'hello, world!', [])
|
203
217
|
end
|
204
218
|
|
205
219
|
def test_simple_pop_with_no_job_found
|
@@ -226,7 +240,7 @@ class TestBazaRb < Minitest::Test
|
|
226
240
|
.with(query: { job: })
|
227
241
|
.to_return(
|
228
242
|
status: 206,
|
229
|
-
headers: { 'Content-Range' => 'bytes 0-0/*', '
|
243
|
+
headers: { 'Content-Range' => 'bytes 0-0/*', 'Content-Length' => 0 },
|
230
244
|
body: ''
|
231
245
|
)
|
232
246
|
bin = nil
|
@@ -240,7 +254,6 @@ class TestBazaRb < Minitest::Test
|
|
240
254
|
status: 206,
|
241
255
|
headers: {
|
242
256
|
'Content-Range' => "bytes 0-7/#{bin.size}",
|
243
|
-
'X-Zerocracy-JobId' => job,
|
244
257
|
'Content-Length' => 8
|
245
258
|
},
|
246
259
|
body: bin[0..7]
|
@@ -252,7 +265,6 @@ class TestBazaRb < Minitest::Test
|
|
252
265
|
status: 206,
|
253
266
|
headers: {
|
254
267
|
'Content-Range' => "bytes 8-#{bin.size - 1}/#{bin.size}",
|
255
|
-
'X-Zerocracy-JobId' => job,
|
256
268
|
'Content-Length' => bin.size - 8
|
257
269
|
},
|
258
270
|
body: bin[8..]
|
@@ -317,7 +329,7 @@ class TestBazaRb < Minitest::Test
|
|
317
329
|
def test_simple_pull
|
318
330
|
WebMock.disable_net_connect!
|
319
331
|
stub_request(:get, 'https://example.org/pull/333.fb').to_return(
|
320
|
-
status: 200, body: 'hello, world!'
|
332
|
+
status: 200, body: 'hello, world!', headers: {}
|
321
333
|
)
|
322
334
|
assert(
|
323
335
|
fake_baza.pull(333).start_with?('hello')
|
@@ -326,13 +338,15 @@ class TestBazaRb < Minitest::Test
|
|
326
338
|
|
327
339
|
def test_simple_lock_success
|
328
340
|
WebMock.disable_net_connect!
|
329
|
-
stub_request(:get, 'https://example.org/
|
341
|
+
stub_request(:get, 'https://example.org/csrf').to_return(body: 'token')
|
342
|
+
stub_request(:post, %r{https://example.org/lock/name}).to_return(status: 302)
|
330
343
|
fake_baza.lock('name', 'owner')
|
331
344
|
end
|
332
345
|
|
333
346
|
def test_simple_lock_failure
|
334
347
|
WebMock.disable_net_connect!
|
335
|
-
stub_request(:get, 'https://example.org/
|
348
|
+
stub_request(:get, 'https://example.org/csrf').to_return(body: 'token')
|
349
|
+
stub_request(:post, %r{https://example.org/lock/name}).to_return(status: 409)
|
336
350
|
assert_raises(StandardError) do
|
337
351
|
fake_baza.lock('name', 'owner')
|
338
352
|
end
|
@@ -446,7 +460,7 @@ class TestBazaRb < Minitest::Test
|
|
446
460
|
file = File.join(dir, 'test.txt')
|
447
461
|
File.write(file, 'test content')
|
448
462
|
stub_request(:put, 'https://example.org:443/durables/42')
|
449
|
-
.with(headers: { 'X-Zerocracy-Token' => '000' }
|
463
|
+
.with(headers: { 'X-Zerocracy-Token' => '000' })
|
450
464
|
.to_return(status: 200)
|
451
465
|
fake_baza.durable_save(42, file)
|
452
466
|
end
|
@@ -458,15 +472,41 @@ class TestBazaRb < Minitest::Test
|
|
458
472
|
file = File.join(dir, 'loaded.txt')
|
459
473
|
stub_request(:get, 'https://example.org:443/durables/42')
|
460
474
|
.with(headers: { 'X-Zerocracy-Token' => '000' })
|
461
|
-
.to_return(status: 200, body: 'loaded content')
|
475
|
+
.to_return(status: 200, body: 'loaded content', headers: {})
|
462
476
|
fake_baza.durable_load(42, file)
|
463
477
|
assert_equal('loaded content', File.read(file))
|
464
478
|
end
|
465
479
|
end
|
466
480
|
|
481
|
+
def test_durable_load_in_chunks
|
482
|
+
WebMock.disable_net_connect!
|
483
|
+
Dir.mktmpdir do |dir|
|
484
|
+
file = File.join(dir, 'loaded.txt')
|
485
|
+
stub_request(:get, 'https://example.org:443/durables/42').to_return(
|
486
|
+
{ status: 206, body: '', headers: { 'Content-Range' => 'bytes 0-0/*', 'Content-Length' => '0' } },
|
487
|
+
{ status: 206, body: 'привет', headers: { 'Content-Range' => 'bytes 0-5/11', 'Content-Length' => '5' } },
|
488
|
+
{ status: 206, body: ' друг', headers: { 'Content-Range' => 'bytes 6-10/11', 'Content-Length' => '5' } }
|
489
|
+
)
|
490
|
+
fake_baza.durable_load(42, file)
|
491
|
+
assert_equal('привет друг', File.read(file))
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def test_durable_load_with_broken_compression
|
496
|
+
WebMock.disable_net_connect!
|
497
|
+
Dir.mktmpdir do |dir|
|
498
|
+
file = File.join(dir, 'loaded.txt')
|
499
|
+
stub_request(:get, 'https://example.org:443/durables/42').to_return(
|
500
|
+
status: 200, body: 'this is not gzip!', headers: { 'Content-Encoding' => 'gzip' }
|
501
|
+
)
|
502
|
+
assert_raises(BazaRb::BadCompression) { fake_baza.durable_load(42, file) }
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
467
506
|
def test_durable_lock
|
468
507
|
WebMock.disable_net_connect!
|
469
|
-
stub_request(:get, 'https://example.org
|
508
|
+
stub_request(:get, 'https://example.org/csrf').to_return(body: 'token')
|
509
|
+
stub_request(:post, %r{https://example.org:443/durables/42/lock})
|
470
510
|
.with(headers: { 'X-Zerocracy-Token' => '000' })
|
471
511
|
.to_return(status: 302)
|
472
512
|
fake_baza.durable_lock(42, 'test-owner')
|
@@ -474,7 +514,8 @@ class TestBazaRb < Minitest::Test
|
|
474
514
|
|
475
515
|
def test_durable_unlock
|
476
516
|
WebMock.disable_net_connect!
|
477
|
-
stub_request(:get, 'https://example.org
|
517
|
+
stub_request(:get, 'https://example.org/csrf').to_return(body: 'token')
|
518
|
+
stub_request(:post, %r{https://example.org:443/durables/42/unlock})
|
478
519
|
.with(headers: { 'X-Zerocracy-Token' => '000' })
|
479
520
|
.to_return(status: 302)
|
480
521
|
fake_baza.durable_unlock(42, 'test-owner')
|
@@ -630,8 +671,7 @@ class TestBazaRb < Minitest::Test
|
|
630
671
|
body: 'data'
|
631
672
|
)
|
632
673
|
.to_return(status: 200, body: '123')
|
633
|
-
|
634
|
-
assert_equal(123, id)
|
674
|
+
baza.push('test', 'data', [])
|
635
675
|
end
|
636
676
|
|
637
677
|
private
|
@@ -663,8 +703,8 @@ class TestBazaRb < Minitest::Test
|
|
663
703
|
req
|
664
704
|
end
|
665
705
|
|
666
|
-
def fake_baza
|
667
|
-
BazaRb.new('example.org', 443, '000', loog: Loog::NULL)
|
706
|
+
def fake_baza(compress: true)
|
707
|
+
BazaRb.new('example.org', 443, '000', loog: Loog::NULL, compress:)
|
668
708
|
end
|
669
709
|
|
670
710
|
def fake_name
|