xfrtuc 0.0.13 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +29 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +13 -0
- data/.rubocop_standardrb.yml +1983 -0
- data/.rubocop_standardrb_overrides.yml +31 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +142 -0
- data/CODEOWNERS +4 -0
- data/Gemfile +10 -1
- data/README.md +58 -0
- data/lib/xfrtuc/errors.rb +19 -0
- data/lib/xfrtuc/version.rb +3 -1
- data/lib/xfrtuc.rb +90 -36
- data/spec/spec_helper.rb +20 -18
- data/spec/xfrtuc_spec.rb +332 -502
- data/xfrtuc.gemspec +14 -16
- metadata +15 -54
- data/.circleci/config.yml +0 -16
data/spec/xfrtuc_spec.rb
CHANGED
|
@@ -1,372 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
require 'spec_helper'
|
|
3
|
-
require 'sham_rack'
|
|
1
|
+
# frozen_string_literal: true
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class FakeTransferatu
|
|
8
|
-
attr_reader :groups
|
|
9
|
-
|
|
10
|
-
def headers
|
|
11
|
-
{ content_type: 'application/json' }
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def initialize(*users)
|
|
15
|
-
@groups = []
|
|
16
|
-
@transfers = {}
|
|
17
|
-
@schedules = {}
|
|
18
|
-
@users = users
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def active_groups
|
|
22
|
-
@groups.reject { |g| g[:deleted] }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def find_transfer(group_name, &block)
|
|
26
|
-
@transfers[group_name].find(&block)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def last_transfer(group_name)
|
|
30
|
-
@transfers[group_name].last
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def last_schedule(group_name)
|
|
34
|
-
@schedules[group_name].last
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def add_group(name, log_url=nil)
|
|
38
|
-
existing_group = @groups.find { |g| g[:name] == name }
|
|
39
|
-
if existing_group
|
|
40
|
-
if existing_group[:deleted]
|
|
41
|
-
# undelete
|
|
42
|
-
existing_group.delete(:deleted)
|
|
43
|
-
[201, headers, [ existing_group.to_json ] ]
|
|
44
|
-
else
|
|
45
|
-
[409, headers, [ { id: :conflict, message: "group #{name} already exists" }.to_json ] ]
|
|
46
|
-
end
|
|
47
|
-
else
|
|
48
|
-
group = { name: name, log_input_url: log_url }
|
|
49
|
-
@groups << group
|
|
50
|
-
@transfers[name] = []
|
|
51
|
-
@schedules[name] = []
|
|
52
|
-
[201, headers, [ group.to_json ] ]
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def delete_group(name)
|
|
57
|
-
target = @groups.find { |g| g[:name] == name }
|
|
58
|
-
if target && target[:deleted]
|
|
59
|
-
[410, headers, []]
|
|
60
|
-
elsif target.nil?
|
|
61
|
-
[404, headers, []]
|
|
62
|
-
else
|
|
63
|
-
target[:deleted] = true
|
|
64
|
-
[200, headers, [target.to_json]]
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def list_groups
|
|
69
|
-
[200, headers, [@groups.to_json]]
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def get_group(name)
|
|
73
|
-
[200, headers, [@groups.find { |g| g[:name] == name }.to_json]]
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def list_transfers(group_name)
|
|
77
|
-
group = @groups.find { |g| g[:name] == group_name }
|
|
78
|
-
if group.nil?
|
|
79
|
-
[404, headers, []]
|
|
80
|
-
elsif group[:deleted]
|
|
81
|
-
[410, headers, []]
|
|
82
|
-
else
|
|
83
|
-
transfers = @transfers[group_name]
|
|
84
|
-
[200, headers, [transfers.to_json]]
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def get_transfer(group_name, xfer_id, verbose=false)
|
|
89
|
-
group = @groups.find { |g| g[:name] == group_name }
|
|
90
|
-
if group.nil?
|
|
91
|
-
[404, headers, []]
|
|
92
|
-
elsif group[:deleted]
|
|
93
|
-
[409, headers, []]
|
|
94
|
-
else
|
|
95
|
-
transfer = @transfers[group_name].find { |xfer| xfer[:uuid] == xfer_id }
|
|
96
|
-
if verbose
|
|
97
|
-
result = transfer.dup
|
|
98
|
-
result[:logs] = []
|
|
99
|
-
transfer = result
|
|
100
|
-
end
|
|
101
|
-
[200, headers, [transfer.to_json]]
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def add_transfer(group_name, transfer)
|
|
106
|
-
unless @transfers.has_key? group_name
|
|
107
|
-
return [404, headers, []]
|
|
108
|
-
end
|
|
109
|
-
xfer = { uuid: SecureRandom.uuid }
|
|
110
|
-
%w(from_type from_url from_name to_type to_url to_name log_input_url).each do |key|
|
|
111
|
-
xfer[key.to_sym] = transfer[key]
|
|
112
|
-
end
|
|
113
|
-
if transfer.has_key? 'num_keep'
|
|
114
|
-
xfer[:num_keep] = transfer['num_keep']
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
@transfers[group_name] << xfer
|
|
118
|
-
[201, {}, [xfer.to_json]]
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def delete_transfer(group_name, xfer_id)
|
|
122
|
-
unless @transfers.has_key? group_name
|
|
123
|
-
return [404, headers, []]
|
|
124
|
-
end
|
|
125
|
-
xfer = @transfers[group_name].find { |item| item[:uuid] == xfer_id }
|
|
126
|
-
if xfer.nil?
|
|
127
|
-
return [404, headers, []]
|
|
128
|
-
else
|
|
129
|
-
@transfers[group_name].delete xfer
|
|
130
|
-
return [200, headers, [ xfer.to_json ]]
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def take_transfer_action(action, args, group_name, xfer_id)
|
|
135
|
-
unless @transfers.has_key? group_name
|
|
136
|
-
return [404, headers, []]
|
|
137
|
-
end
|
|
138
|
-
xfer = @transfers[group_name].find { |item| item[:uuid] == xfer_id }
|
|
139
|
-
if xfer.nil?
|
|
140
|
-
return [404, headers, []]
|
|
141
|
-
else
|
|
142
|
-
case action
|
|
143
|
-
when 'cancel' then
|
|
144
|
-
now = Time.now
|
|
145
|
-
xfer[:canceled_at] = now
|
|
146
|
-
return [201, headers, [ { canceled_at: now }.to_json ]]
|
|
147
|
-
when 'public-url' then
|
|
148
|
-
expires_at = if args.has_key? 'ttl'
|
|
149
|
-
Time.now + args['ttl'].to_i
|
|
150
|
-
else
|
|
151
|
-
Time.now + (10 * 60)
|
|
152
|
-
end
|
|
153
|
-
url = "https://example.com/backup/#{xfer[:uuid]}"
|
|
154
|
-
return [201, headers, [ { url: url, expires_at: expires_at }.to_json ]]
|
|
155
|
-
else
|
|
156
|
-
return [404, headers, []]
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def add_schedule(group_name, schedule)
|
|
162
|
-
unless @schedules.has_key? group_name
|
|
163
|
-
return [404, headers, []]
|
|
164
|
-
end
|
|
165
|
-
sched = { uuid: SecureRandom.uuid }
|
|
166
|
-
%w(name callback_url days hour timezone).each do |key|
|
|
167
|
-
sched[key.to_sym] = schedule[key]
|
|
168
|
-
end
|
|
169
|
-
%w(retain_weeks retain_months).each do |key|
|
|
170
|
-
sched[key.to_sym] = schedule[key] if schedule.has_key? key
|
|
171
|
-
end
|
|
172
|
-
@schedules[group_name] << sched
|
|
173
|
-
[201, {}, [sched.to_json]]
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def delete_schedule(group_name, schedule_id)
|
|
177
|
-
unless @schedules.has_key? group_name
|
|
178
|
-
return [404, headers, []]
|
|
179
|
-
end
|
|
180
|
-
schedule = @schedules[group_name].find { |item| item[:uuid] == schedule_id }
|
|
181
|
-
if schedule.nil?
|
|
182
|
-
return [404, headers, []]
|
|
183
|
-
else
|
|
184
|
-
@schedules[group_name].delete schedule
|
|
185
|
-
return [200, headers, [ schedule.to_json ]]
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def list_schedules(group_name)
|
|
190
|
-
group = @groups.find { |g| g[:name] == group_name }
|
|
191
|
-
if group.nil?
|
|
192
|
-
[404, headers, []]
|
|
193
|
-
elsif group[:deleted]
|
|
194
|
-
[410, headers, []]
|
|
195
|
-
else
|
|
196
|
-
schedules = @schedules[group_name]
|
|
197
|
-
[200, headers, [schedules.to_json]]
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def get_schedule(group_name, sched_id)
|
|
202
|
-
group = @groups.find { |g| g[:name] == group_name }
|
|
203
|
-
if group.nil?
|
|
204
|
-
[404, headers, []]
|
|
205
|
-
elsif group[:deleted]
|
|
206
|
-
[410, headers, []]
|
|
207
|
-
else
|
|
208
|
-
sched = @schedules[group_name].find { |s| s[:uuid] == sched_id }
|
|
209
|
-
if sched.nil?
|
|
210
|
-
[404, headers, []]
|
|
211
|
-
else
|
|
212
|
-
[200, headers, [sched.to_json]]
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def call(env)
|
|
218
|
-
unless verify_auth(env)
|
|
219
|
-
return [401, headers, ["Not authorized"]]
|
|
220
|
-
end
|
|
221
|
-
case path(env)
|
|
222
|
-
when %r{/groups/[^/]+/transfers/[^/]+/actions} then
|
|
223
|
-
transfers_actions_endpoint(env)
|
|
224
|
-
when %r{/groups/[^/]+/transfers} then
|
|
225
|
-
transfers_endpoint(env)
|
|
226
|
-
when %r{/groups/[^/]+/schedules} then
|
|
227
|
-
schedules_endpoint(env)
|
|
228
|
-
when %r{/groups} then
|
|
229
|
-
groups_endpoint(env)
|
|
230
|
-
else
|
|
231
|
-
[404, headers, []]
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def transfers_actions_endpoint(env)
|
|
236
|
-
path = path(env)
|
|
237
|
-
group_name, xfer_id, action =
|
|
238
|
-
path.match(%r{\A/groups/(.*)/transfers/(.*)/actions/(.*)\z}) && [$1, $2, $3]
|
|
239
|
-
verb = verb(env)
|
|
240
|
-
if verb == 'POST'
|
|
241
|
-
body = body(env)
|
|
242
|
-
args = JSON.parse(body) unless body.empty?
|
|
243
|
-
take_transfer_action(action, args, group_name, xfer_id)
|
|
244
|
-
else
|
|
245
|
-
[405, headers, []]
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def transfers_endpoint(env)
|
|
250
|
-
path = path(env)
|
|
251
|
-
group_name, xfer_id = path.match(%r{\A/groups/(.*)/transfers(?:/(.*))?\z}) && [$1, $2]
|
|
252
|
-
verb = verb(env)
|
|
253
|
-
if verb == 'POST'
|
|
254
|
-
body = body(env)
|
|
255
|
-
xfer = JSON.parse(body)
|
|
256
|
-
unless xfer_id.nil?
|
|
257
|
-
[405, headers, []]
|
|
258
|
-
end
|
|
259
|
-
add_transfer(group_name, xfer)
|
|
260
|
-
elsif verb == 'DELETE'
|
|
261
|
-
unless group_name && xfer_id
|
|
262
|
-
return [404, headers, []]
|
|
263
|
-
end
|
|
264
|
-
delete_transfer(group_name, xfer_id)
|
|
265
|
-
elsif verb == 'GET'
|
|
266
|
-
if xfer_id.nil?
|
|
267
|
-
list_transfers(group_name)
|
|
268
|
-
else
|
|
269
|
-
get_transfer(group_name, xfer_id, params(env)['verbose'] == 'true')
|
|
270
|
-
end
|
|
271
|
-
else
|
|
272
|
-
[405, headers, []]
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
def groups_endpoint(env)
|
|
277
|
-
path = path(env)
|
|
278
|
-
verb = verb(env)
|
|
279
|
-
|
|
280
|
-
group_name = path.match(%r{\A/groups/(.*)\z}) && $1
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require "spec_helper"
|
|
281
5
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
end
|
|
288
|
-
elsif verb == 'POST'
|
|
289
|
-
body = body(env)
|
|
290
|
-
data = JSON.parse(body)
|
|
291
|
-
add_group(data["name"], data["log_input_url"])
|
|
292
|
-
elsif verb == 'DELETE'
|
|
293
|
-
name = path.match(%r{\A/groups/(.*)\z}) && $1
|
|
294
|
-
unless name
|
|
295
|
-
return [404, headers, []]
|
|
296
|
-
end
|
|
297
|
-
delete_group(name)
|
|
298
|
-
else
|
|
299
|
-
[405, headers, []]
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
def schedules_endpoint(env)
|
|
304
|
-
path = path(env)
|
|
305
|
-
group_name, sched_id = path.match(%r{\A/groups/(.*)/schedules(?:/(.*))?\z}) && [$1, $2]
|
|
306
|
-
verb = verb(env)
|
|
307
|
-
if %w(POST PUT).include? verb
|
|
308
|
-
body = body(env)
|
|
309
|
-
sched = JSON.parse(body)
|
|
310
|
-
unless sched_id.nil?
|
|
311
|
-
[405, headers, []]
|
|
312
|
-
end
|
|
313
|
-
add_schedule(group_name, sched)
|
|
314
|
-
elsif verb == 'DELETE'
|
|
315
|
-
unless group_name && sched_id
|
|
316
|
-
return [404, headers, []]
|
|
317
|
-
end
|
|
318
|
-
delete_schedule(group_name, sched_id)
|
|
319
|
-
elsif verb == 'GET'
|
|
320
|
-
if sched_id.nil?
|
|
321
|
-
list_schedules(group_name)
|
|
322
|
-
else
|
|
323
|
-
get_schedule(group_name, sched_id)
|
|
324
|
-
end
|
|
325
|
-
else
|
|
326
|
-
[405, headers, []]
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
private
|
|
331
|
-
def verify_auth(env)
|
|
332
|
-
auth = Rack::Auth::Basic::Request.new(env)
|
|
333
|
-
if auth.provided? && auth.basic?
|
|
334
|
-
user, password = auth.credentials
|
|
335
|
-
@users.any? { |u| u.name == user && u.password == password }
|
|
336
|
-
end
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
def path(rack_env)
|
|
340
|
-
rack_env['PATH_INFO']
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def verb(rack_env)
|
|
344
|
-
rack_env['REQUEST_METHOD']
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
def params(rack_env)
|
|
348
|
-
Rack::Utils.parse_nested_query rack_env['QUERY_STRING']
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
def body(rack_env)
|
|
352
|
-
raw_body = rack_env["rack.input"].read
|
|
353
|
-
rack_env["rack.input"].rewind
|
|
354
|
-
raw_body
|
|
355
|
-
end
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
describe Client do
|
|
359
|
-
let(:username) { 'reginald' }
|
|
360
|
-
let(:password) { 'hunter2' }
|
|
361
|
-
let(:client) { Client.new(username, password) }
|
|
6
|
+
module Xfrtuc
|
|
7
|
+
RSpec.describe Client do
|
|
8
|
+
let(:username) { "reginald" }
|
|
9
|
+
let(:password) { "hunter2" }
|
|
10
|
+
let(:client) { described_class.new(username, password) }
|
|
362
11
|
|
|
363
12
|
describe "#group" do
|
|
364
13
|
context "with an argument" do
|
|
365
|
-
let(:group_name) {
|
|
14
|
+
let(:group_name) { "foo" }
|
|
366
15
|
|
|
367
16
|
it "returns a new client rooted at that group's base URL" do
|
|
368
17
|
group_client = client.group(group_name)
|
|
369
|
-
expect(group_client).to be_instance_of(
|
|
18
|
+
expect(group_client).to be_instance_of(described_class)
|
|
370
19
|
expect(group_client.base_url).to eq(client.base_url +
|
|
371
20
|
"/groups/#{CGI.escape(group_name)}")
|
|
372
21
|
end
|
|
@@ -392,55 +41,52 @@ module Xfrtuc
|
|
|
392
41
|
end
|
|
393
42
|
end
|
|
394
43
|
|
|
395
|
-
describe "api interactions" do
|
|
396
|
-
let(:username)
|
|
397
|
-
let(:password)
|
|
398
|
-
let(:
|
|
399
|
-
let(:
|
|
400
|
-
let(:
|
|
401
|
-
let(:client) { Client.new(username, password, "https://#{host}") }
|
|
402
|
-
|
|
403
|
-
before do
|
|
404
|
-
ShamRack.at(host, 443).mount(fakesferatu)
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
after do
|
|
408
|
-
ShamRack.unmount_all
|
|
409
|
-
end
|
|
44
|
+
RSpec.describe "api interactions" do
|
|
45
|
+
let(:username) { "vivian" }
|
|
46
|
+
let(:password) { "hunter2" }
|
|
47
|
+
let(:host) { "transferatu.example.com" }
|
|
48
|
+
let(:base_url) { "https://#{host}" }
|
|
49
|
+
let(:client) { Client.new(username, password, base_url) }
|
|
410
50
|
|
|
411
51
|
describe Group do
|
|
412
|
-
let(:group_name)
|
|
52
|
+
let(:group_name) { "edna" }
|
|
413
53
|
let(:log_input_url) { "https://token:t.foo@logplex.example.com/logs" }
|
|
414
54
|
|
|
415
55
|
describe "#create" do
|
|
416
56
|
it "creates a new group" do
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
57
|
+
WebMock.stub_request(:post, "#{base_url}/groups")
|
|
58
|
+
.with(basic_auth: [username, password],
|
|
59
|
+
body: { name: group_name, log_input_url: log_input_url },)
|
|
60
|
+
.to_return_json(status: 201,
|
|
61
|
+
body: { name: group_name, log_input_url: log_input_url },)
|
|
62
|
+
|
|
63
|
+
result = client.group.create(group_name, log_input_url)
|
|
64
|
+
expect(result["name"]).to eq(group_name)
|
|
65
|
+
expect(result["log_input_url"]).to eq(log_input_url)
|
|
421
66
|
end
|
|
422
67
|
end
|
|
423
68
|
|
|
424
69
|
describe "#list" do
|
|
425
|
-
before do
|
|
426
|
-
fakesferatu.add_group('g1')
|
|
427
|
-
fakesferatu.add_group('g2')
|
|
428
|
-
end
|
|
429
|
-
|
|
430
70
|
it "lists existing groups" do
|
|
71
|
+
groups = [{ name: "g1" }, { name: "g2" }]
|
|
72
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
73
|
+
.with(basic_auth: [username, password])
|
|
74
|
+
.to_return_json(status: 200, body: groups)
|
|
75
|
+
|
|
431
76
|
result = client.group.list
|
|
432
77
|
expect(result.count).to eq(2)
|
|
433
|
-
expect(result.first["name"]).to eq(
|
|
434
|
-
expect(result.last["name"]).to eq(
|
|
78
|
+
expect(result.first["name"]).to eq("g1")
|
|
79
|
+
expect(result.last["name"]).to eq("g2")
|
|
435
80
|
end
|
|
436
81
|
end
|
|
437
82
|
|
|
438
83
|
describe "#info" do
|
|
439
|
-
before do
|
|
440
|
-
fakesferatu.add_group(group_name, log_input_url)
|
|
441
|
-
end
|
|
442
|
-
|
|
443
84
|
it "returns details for the given group" do
|
|
85
|
+
group = { name: group_name, log_input_url: log_input_url }
|
|
86
|
+
WebMock.stub_request(:get, "#{base_url}/groups/#{group_name}")
|
|
87
|
+
.with(basic_auth: [username, password])
|
|
88
|
+
.to_return_json(status: 200, body: group)
|
|
89
|
+
|
|
444
90
|
info = client.group.info(group_name)
|
|
445
91
|
expect(info["name"]).to eq(group_name)
|
|
446
92
|
expect(info["log_input_url"]).to eq(log_input_url)
|
|
@@ -448,63 +94,82 @@ module Xfrtuc
|
|
|
448
94
|
end
|
|
449
95
|
|
|
450
96
|
describe "#delete" do
|
|
451
|
-
before do
|
|
452
|
-
fakesferatu.add_group(group_name, log_input_url)
|
|
453
|
-
end
|
|
454
|
-
|
|
455
97
|
it "deletes the given group" do
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
98
|
+
WebMock.stub_request(:delete, "#{base_url}/groups/#{group_name}")
|
|
99
|
+
.with(basic_auth: [username, password])
|
|
100
|
+
.to_return_json(status: 200, body: { name: group_name, deleted: true })
|
|
101
|
+
|
|
102
|
+
result = client.group.delete(group_name)
|
|
103
|
+
expect(result["name"]).to eq(group_name)
|
|
459
104
|
end
|
|
460
105
|
end
|
|
461
106
|
end
|
|
462
107
|
|
|
463
108
|
describe Transfer do
|
|
464
|
-
let(:g)
|
|
465
|
-
let(:xfer_data) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
end
|
|
109
|
+
let(:g) { "edna" }
|
|
110
|
+
let(:xfer_data) {
|
|
111
|
+
{ from_url: "postgres:///test1",
|
|
112
|
+
from_name: "earl", from_type: "pg_dump",
|
|
113
|
+
to_url: "postgres:///test2",
|
|
114
|
+
to_name: "mildred", to_type: "pg_restore", }
|
|
115
|
+
}
|
|
116
|
+
let(:xfer_id) { SecureRandom.uuid }
|
|
473
117
|
|
|
474
118
|
describe "#create" do
|
|
475
119
|
it "creates a new transfer" do
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
120
|
+
response = xfer_data.merge(uuid: xfer_id)
|
|
121
|
+
WebMock.stub_request(:post, "#{base_url}/groups/#{g}/transfers")
|
|
122
|
+
.with(basic_auth: [username, password])
|
|
123
|
+
.to_return_json(status: 201, body: response)
|
|
124
|
+
|
|
125
|
+
result = client.group(g).transfer.create(xfer_data)
|
|
126
|
+
xfer_data.each do |k, v|
|
|
127
|
+
expect(result[k.to_s]).to eq(v)
|
|
480
128
|
end
|
|
481
129
|
end
|
|
482
130
|
|
|
483
131
|
it "accepts an optional log_input_url" do
|
|
484
132
|
log_url = "https://example.com/logs"
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
133
|
+
response = xfer_data.merge(uuid: xfer_id, log_input_url: log_url)
|
|
134
|
+
WebMock.stub_request(:post, "#{base_url}/groups/#{g}/transfers")
|
|
135
|
+
.with(basic_auth: [username, password],
|
|
136
|
+
body: hash_including("log_input_url" => log_url),)
|
|
137
|
+
.to_return_json(status: 201, body: response)
|
|
138
|
+
|
|
139
|
+
result = client.group(g).transfer.create(xfer_data.merge(log_input_url: log_url))
|
|
140
|
+
expect(result["log_input_url"]).to eq(log_url)
|
|
488
141
|
end
|
|
489
142
|
|
|
490
143
|
it "accepts an optional num_keep" do
|
|
491
144
|
num_keep = 3
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
145
|
+
response = xfer_data.merge(uuid: xfer_id, num_keep: num_keep)
|
|
146
|
+
WebMock.stub_request(:post, "#{base_url}/groups/#{g}/transfers")
|
|
147
|
+
.with(basic_auth: [username, password],
|
|
148
|
+
body: hash_including("num_keep" => num_keep),)
|
|
149
|
+
.to_return_json(status: 201, body: response)
|
|
150
|
+
|
|
151
|
+
result = client.group(g).transfer.create(xfer_data.merge(num_keep: num_keep))
|
|
152
|
+
expect(result["num_keep"]).to eq(num_keep)
|
|
495
153
|
end
|
|
496
|
-
end
|
|
497
154
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
155
|
+
it "raises ArgumentError for unsupported options" do
|
|
156
|
+
expect {
|
|
157
|
+
client.group(g).transfer.create(xfer_data.merge(bogus: "value"))
|
|
158
|
+
}.to raise_error(ArgumentError, /Unsupported option/)
|
|
501
159
|
end
|
|
160
|
+
end
|
|
502
161
|
|
|
162
|
+
describe "#list" do
|
|
503
163
|
it "lists existing transfers" do
|
|
504
|
-
xfers =
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
164
|
+
xfers = Array.new(2) { xfer_data.merge(uuid: SecureRandom.uuid) }
|
|
165
|
+
WebMock.stub_request(:get, "#{base_url}/groups/#{g}/transfers")
|
|
166
|
+
.with(basic_auth: [username, password])
|
|
167
|
+
.to_return_json(status: 200, body: xfers)
|
|
168
|
+
|
|
169
|
+
result = client.group(g).transfer.list
|
|
170
|
+
expect(result.count).to eq(2)
|
|
171
|
+
result.each do |xfer|
|
|
172
|
+
xfer_data.each do |k, v|
|
|
508
173
|
expect(xfer[k.to_s]).to eq(v)
|
|
509
174
|
end
|
|
510
175
|
end
|
|
@@ -512,118 +177,283 @@ module Xfrtuc
|
|
|
512
177
|
end
|
|
513
178
|
|
|
514
179
|
describe "#info" do
|
|
515
|
-
before do
|
|
516
|
-
fakesferatu.add_transfer(g, Hash[xfer_data.map { |k, v| [k.to_s, v] }])
|
|
517
|
-
end
|
|
518
|
-
|
|
519
180
|
it "gets info for an existing transfer" do
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
181
|
+
response = xfer_data.merge(uuid: xfer_id)
|
|
182
|
+
WebMock.stub_request(:get, "#{base_url}/groups/#{g}/transfers/#{xfer_id}")
|
|
183
|
+
.with(basic_auth: [username, password],
|
|
184
|
+
query: { "verbose" => "false" },)
|
|
185
|
+
.to_return_json(status: 200, body: response)
|
|
186
|
+
|
|
187
|
+
xfer = client.group(g).transfer.info(xfer_id)
|
|
188
|
+
xfer_data.each do |k, v|
|
|
523
189
|
expect(xfer[k.to_s]).to eq(v)
|
|
524
190
|
end
|
|
525
191
|
expect(xfer["logs"]).to be_nil
|
|
526
192
|
end
|
|
527
193
|
|
|
528
194
|
it "includes logs when verbose mode is requested" do
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
195
|
+
response = xfer_data.merge(uuid: xfer_id, logs: [])
|
|
196
|
+
WebMock.stub_request(:get, "#{base_url}/groups/#{g}/transfers/#{xfer_id}")
|
|
197
|
+
.with(basic_auth: [username, password],
|
|
198
|
+
query: { "verbose" => "true" },)
|
|
199
|
+
.to_return_json(status: 200, body: response)
|
|
200
|
+
|
|
201
|
+
xfer = client.group(g).transfer.info(xfer_id, verbose: true)
|
|
202
|
+
xfer_data.each do |k, v|
|
|
532
203
|
expect(xfer[k.to_s]).to eq(v)
|
|
533
204
|
end
|
|
534
205
|
expect(xfer["logs"]).not_to be_nil
|
|
535
206
|
end
|
|
536
|
-
end
|
|
537
207
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
208
|
+
it "raises ArgumentError for unsupported options" do
|
|
209
|
+
expect {
|
|
210
|
+
client.group(g).transfer.info(xfer_id, bogus: "value")
|
|
211
|
+
}.to raise_error(ArgumentError, /Unsupported option/)
|
|
541
212
|
end
|
|
213
|
+
end
|
|
542
214
|
|
|
215
|
+
describe "#delete" do
|
|
543
216
|
it "deletes the given transfer" do
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
217
|
+
response = xfer_data.merge(uuid: xfer_id)
|
|
218
|
+
WebMock.stub_request(:delete, "#{base_url}/groups/#{g}/transfers/#{xfer_id}")
|
|
219
|
+
.with(basic_auth: [username, password])
|
|
220
|
+
.to_return_json(status: 200, body: response)
|
|
221
|
+
|
|
222
|
+
result = client.group(g).transfer.delete(xfer_id)
|
|
223
|
+
expect(result["uuid"]).to eq(xfer_id)
|
|
547
224
|
end
|
|
548
225
|
end
|
|
549
226
|
|
|
550
227
|
describe "#cancel" do
|
|
551
|
-
before do
|
|
552
|
-
fakesferatu.add_transfer(g, Hash[xfer_data.map { |k, v| [k.to_s, v] }])
|
|
553
|
-
end
|
|
554
|
-
|
|
555
228
|
it "cancels the given transfer" do
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
229
|
+
now = Time.now
|
|
230
|
+
WebMock.stub_request(:post, "#{base_url}/groups/#{g}/transfers/#{xfer_id}/actions/cancel")
|
|
231
|
+
.with(basic_auth: [username, password])
|
|
232
|
+
.to_return_json(status: 201, body: { canceled_at: now })
|
|
233
|
+
|
|
234
|
+
cancel_data = client.group(g).transfer.cancel(xfer_id)
|
|
559
235
|
canceled_at = Time.parse(cancel_data["canceled_at"])
|
|
560
|
-
expect(canceled_at).to be_within(60).of(
|
|
236
|
+
expect(canceled_at).to be_within(60).of(now)
|
|
561
237
|
end
|
|
562
238
|
end
|
|
563
239
|
|
|
564
240
|
describe "#public_url" do
|
|
565
|
-
before do
|
|
566
|
-
fakesferatu.add_transfer(g, Hash[xfer_data.map { |k, v| [k.to_s, v] }])
|
|
567
|
-
end
|
|
568
|
-
|
|
569
241
|
it "provides a public url for the given transfer" do
|
|
570
|
-
|
|
571
|
-
|
|
242
|
+
url = "https://example.com/backup/#{xfer_id}"
|
|
243
|
+
expires_at = Time.now + (10 * 60)
|
|
244
|
+
WebMock.stub_request(:post, "#{base_url}/groups/#{g}/transfers/#{xfer_id}/actions/public-url")
|
|
245
|
+
.with(basic_auth: [username, password])
|
|
246
|
+
.to_return_json(status: 201, body: { url: url, expires_at: expires_at })
|
|
247
|
+
|
|
248
|
+
url_data = client.group(g).transfer.public_url(xfer_id)
|
|
572
249
|
expect { URI.parse(url_data["url"]) }.not_to raise_error
|
|
573
250
|
end
|
|
574
251
|
|
|
575
252
|
it "supports an optional ttl parameter" do
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
253
|
+
url = "https://example.com/backup/#{xfer_id}"
|
|
254
|
+
now = Time.now
|
|
255
|
+
expires_at = now + (5 * 60)
|
|
256
|
+
WebMock.stub_request(:post, "#{base_url}/groups/#{g}/transfers/#{xfer_id}/actions/public-url")
|
|
257
|
+
.with(basic_auth: [username, password],
|
|
258
|
+
body: { ttl: 300 }.to_json,)
|
|
259
|
+
.to_return_json(status: 201, body: { url: url, expires_at: expires_at })
|
|
260
|
+
|
|
261
|
+
url_data = client.group(g).transfer.public_url(xfer_id, ttl: 5 * 60)
|
|
262
|
+
expires = Time.parse(url_data["expires_at"])
|
|
263
|
+
expect(expires).to be_within(60).of(now + (5 * 60))
|
|
581
264
|
end
|
|
582
265
|
end
|
|
583
266
|
end
|
|
584
267
|
|
|
585
|
-
describe
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
268
|
+
describe "error handling" do
|
|
269
|
+
it "does not raise for 2xx responses" do
|
|
270
|
+
[200, 201, 204].each do |status|
|
|
271
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
272
|
+
.with(basic_auth: [username, password])
|
|
273
|
+
.to_return_json(status: status, body: [])
|
|
274
|
+
|
|
275
|
+
expect { client.group.list }.not_to raise_error
|
|
276
|
+
WebMock.reset!
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "raises BadRequest for 400" do
|
|
281
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
282
|
+
.with(basic_auth: [username, password])
|
|
283
|
+
.to_return(status: 400, body: '{"error":"bad request"}')
|
|
284
|
+
|
|
285
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::BadRequest, /got 400/)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
it "raises NotFound for 404" do
|
|
289
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
290
|
+
.with(basic_auth: [username, password])
|
|
291
|
+
.to_return(status: 404, body: '{"error":"not found"}')
|
|
292
|
+
|
|
293
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::NotFound, /got 404/)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
it "raises Conflict for 409" do
|
|
297
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
298
|
+
.with(basic_auth: [username, password])
|
|
299
|
+
.to_return(status: 409, body: '{"error":"conflict"}')
|
|
300
|
+
|
|
301
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::Conflict, /got 409/)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "raises Gone for 410" do
|
|
305
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
306
|
+
.with(basic_auth: [username, password])
|
|
307
|
+
.to_return(status: 410, body: '{"error":"gone"}')
|
|
308
|
+
|
|
309
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::Gone, /got 410/)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "raises ClientError for other 4xx responses" do
|
|
313
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
314
|
+
.with(basic_auth: [username, password])
|
|
315
|
+
.to_return(status: 422, body: '{"error":"unprocessable"}')
|
|
316
|
+
|
|
317
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::ClientError, /got 422/)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it "raises ServerError for 500" do
|
|
321
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
322
|
+
.with(basic_auth: [username, password])
|
|
323
|
+
.to_return(status: 500, body: '{"error":"internal"}')
|
|
324
|
+
|
|
325
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::ServerError, /got 500/)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "raises ServiceUnavailable for 503" do
|
|
329
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
330
|
+
.with(basic_auth: [username, password])
|
|
331
|
+
.to_return(status: 503, body: '{"error":"unavailable"}')
|
|
332
|
+
|
|
333
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::ServiceUnavailable, /got 503/)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it "ServiceUnavailable is rescuable as ServerError" do
|
|
337
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
338
|
+
.with(basic_auth: [username, password])
|
|
339
|
+
.to_return(status: 503, body: '{"error":"unavailable"}')
|
|
340
|
+
|
|
341
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::ServerError)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it "raises ServerError for other 5xx responses" do
|
|
345
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
346
|
+
.with(basic_auth: [username, password])
|
|
347
|
+
.to_return(status: 502, body: '{"error":"bad gateway"}')
|
|
348
|
+
|
|
349
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::ServerError, /got 502/)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "all HTTP errors are rescuable as Xfrtuc::HTTP::Error" do
|
|
353
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
354
|
+
.with(basic_auth: [username, password])
|
|
355
|
+
.to_return(status: 500, body: '{"error":"internal"}')
|
|
356
|
+
|
|
357
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::Error)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it "raises ConnectionResetError on ECONNRESET" do
|
|
361
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
362
|
+
.with(basic_auth: [username, password])
|
|
363
|
+
.to_raise(Errno::ECONNRESET)
|
|
364
|
+
|
|
365
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::ConnectionResetError)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
it "raises SocketError on connection refused" do
|
|
369
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
370
|
+
.with(basic_auth: [username, password])
|
|
371
|
+
.to_raise(Errno::ECONNREFUSED)
|
|
592
372
|
|
|
593
|
-
|
|
594
|
-
fakesferatu.add_group(g)
|
|
373
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::SocketError)
|
|
595
374
|
end
|
|
596
375
|
|
|
376
|
+
it "raises SocketError on DNS failure" do
|
|
377
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
378
|
+
.with(basic_auth: [username, password])
|
|
379
|
+
.to_raise(SocketError.new("getaddrinfo: Name or service not known"))
|
|
380
|
+
|
|
381
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::SocketError)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
it "raises SocketError on timeout" do
|
|
385
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
386
|
+
.with(basic_auth: [username, password])
|
|
387
|
+
.to_timeout
|
|
388
|
+
|
|
389
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::SocketError)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
it "network errors are rescuable as Xfrtuc::HTTP::Error" do
|
|
393
|
+
WebMock.stub_request(:get, "#{base_url}/groups")
|
|
394
|
+
.with(basic_auth: [username, password])
|
|
395
|
+
.to_raise(Errno::ECONNREFUSED)
|
|
396
|
+
|
|
397
|
+
expect { client.group.list }.to raise_error(Xfrtuc::HTTP::Error)
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
describe Schedule do
|
|
402
|
+
let(:g) { "edna" }
|
|
403
|
+
let(:sched_data) {
|
|
404
|
+
{ name: "my schedule",
|
|
405
|
+
callback_url: "https://example.com/callback/foo",
|
|
406
|
+
hour: 13,
|
|
407
|
+
days: Date::DAYNAMES,
|
|
408
|
+
timezone: "UTC", }
|
|
409
|
+
}
|
|
410
|
+
let(:sched_id) { SecureRandom.uuid }
|
|
411
|
+
|
|
597
412
|
describe "#create" do
|
|
598
413
|
it "creates a new schedule" do
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
414
|
+
response = sched_data.merge(uuid: sched_id)
|
|
415
|
+
WebMock.stub_request(:put, "#{base_url}/groups/#{g}/schedules/#{CGI.escape(sched_data[:name])}")
|
|
416
|
+
.with(basic_auth: [username, password])
|
|
417
|
+
.to_return_json(status: 201, body: response)
|
|
418
|
+
|
|
419
|
+
result = client.group(g).schedule.create(sched_data)
|
|
420
|
+
sched_data.each do |k, v|
|
|
421
|
+
expect(result[k.to_s]).to eq(v)
|
|
603
422
|
end
|
|
604
423
|
end
|
|
605
424
|
|
|
606
425
|
it "accepts an optional retain_weeks and retain_months" do
|
|
607
426
|
retain_weeks = 7
|
|
608
427
|
retain_months = 8
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
428
|
+
response = sched_data.merge(uuid: sched_id, retain_weeks: retain_weeks, retain_months: retain_months)
|
|
429
|
+
WebMock.stub_request(:put, "#{base_url}/groups/#{g}/schedules/#{CGI.escape(sched_data[:name])}")
|
|
430
|
+
.with(basic_auth: [username, password],
|
|
431
|
+
body: hash_including("retain_weeks" => retain_weeks, "retain_months" => retain_months),)
|
|
432
|
+
.to_return_json(status: 201, body: response)
|
|
433
|
+
|
|
434
|
+
result = client.group(g).schedule.create(sched_data.merge(retain_weeks: retain_weeks, retain_months: retain_months))
|
|
435
|
+
expect(result["retain_weeks"]).to eq(retain_weeks)
|
|
436
|
+
expect(result["retain_months"]).to eq(retain_months)
|
|
614
437
|
end
|
|
615
|
-
end
|
|
616
438
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
439
|
+
it "raises ArgumentError for unsupported options" do
|
|
440
|
+
expect {
|
|
441
|
+
client.group(g).schedule.create(sched_data.merge(bogus: "value"))
|
|
442
|
+
}.to raise_error(ArgumentError, /Unsupported option/)
|
|
620
443
|
end
|
|
444
|
+
end
|
|
621
445
|
|
|
446
|
+
describe "#list" do
|
|
622
447
|
it "lists existing schedules" do
|
|
623
|
-
scheds =
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
448
|
+
scheds = Array.new(2) { sched_data.merge(uuid: SecureRandom.uuid) }
|
|
449
|
+
WebMock.stub_request(:get, "#{base_url}/groups/#{g}/schedules")
|
|
450
|
+
.with(basic_auth: [username, password])
|
|
451
|
+
.to_return_json(status: 200, body: scheds)
|
|
452
|
+
|
|
453
|
+
result = client.group(g).schedule.list
|
|
454
|
+
expect(result.count).to eq(2)
|
|
455
|
+
result.each do |sched|
|
|
456
|
+
sched_data.each do |k, v|
|
|
627
457
|
expect(sched[k.to_s]).to eq(v)
|
|
628
458
|
end
|
|
629
459
|
end
|
|
@@ -631,28 +461,28 @@ module Xfrtuc
|
|
|
631
461
|
end
|
|
632
462
|
|
|
633
463
|
describe "#info" do
|
|
634
|
-
before do
|
|
635
|
-
fakesferatu.add_schedule(g, Hash[sched_data.map { |k, v| [k.to_s, v] }])
|
|
636
|
-
end
|
|
637
|
-
|
|
638
464
|
it "gets info for an existing schedule" do
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
465
|
+
response = sched_data.merge(uuid: sched_id)
|
|
466
|
+
WebMock.stub_request(:get, "#{base_url}/groups/#{g}/schedules/#{sched_id}")
|
|
467
|
+
.with(basic_auth: [username, password])
|
|
468
|
+
.to_return_json(status: 200, body: response)
|
|
469
|
+
|
|
470
|
+
sched = client.group(g).schedule.info(sched_id)
|
|
471
|
+
sched_data.each do |k, v|
|
|
642
472
|
expect(sched[k.to_s]).to eq(v)
|
|
643
473
|
end
|
|
644
474
|
end
|
|
645
475
|
end
|
|
646
476
|
|
|
647
477
|
describe "#delete" do
|
|
648
|
-
before do
|
|
649
|
-
fakesferatu.add_schedule(g, Hash[sched_data.map { |k, v| [k.to_s, v] }])
|
|
650
|
-
end
|
|
651
|
-
|
|
652
478
|
it "deletes the given schedule" do
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
479
|
+
response = sched_data.merge(uuid: sched_id)
|
|
480
|
+
WebMock.stub_request(:delete, "#{base_url}/groups/#{g}/schedules/#{sched_id}")
|
|
481
|
+
.with(basic_auth: [username, password])
|
|
482
|
+
.to_return_json(status: 200, body: response)
|
|
483
|
+
|
|
484
|
+
result = client.group(g).schedule.delete(sched_id)
|
|
485
|
+
expect(result["uuid"]).to eq(sched_id)
|
|
656
486
|
end
|
|
657
487
|
end
|
|
658
488
|
end
|