zeppelin 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -3
- data/.travis.yml +2 -1
- data/.yardopts +4 -1
- data/Changelog.md +28 -0
- data/Gemfile +9 -1
- data/Guardfile +10 -0
- data/Rakefile +7 -7
- data/lib/zeppelin.rb +97 -47
- data/lib/zeppelin/middleware.rb +7 -0
- data/lib/zeppelin/middleware/json_parser.rb +37 -0
- data/lib/zeppelin/middleware/response_raise_error.rb +22 -0
- data/lib/zeppelin/version.rb +1 -1
- data/spec/middleware/json_parser_spec.rb +34 -0
- data/spec/middleware/response_raise_error_spec.rb +32 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/zeppelin_spec.rb +470 -0
- data/zeppelin.gemspec +4 -7
- metadata +30 -62
- data/.autotest +0 -15
- data/lib/zeppelin/json_parser_middleware.rb +0 -35
- data/test/json_parser_middleware_test.rb +0 -35
- data/test/test_helper.rb +0 -13
- data/test/zeppelin_test.rb +0 -453
@@ -0,0 +1,22 @@
|
|
1
|
+
class Zeppelin
|
2
|
+
class ResourceNotFound < Faraday::Error::ResourceNotFound
|
3
|
+
end
|
4
|
+
|
5
|
+
class ClientError < Faraday::Error::ClientError
|
6
|
+
end
|
7
|
+
|
8
|
+
module Middleware
|
9
|
+
# Intercept Faraday errors and re-raise our own to hide implementation details
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
class ResponseRaiseError < Faraday::Response::RaiseError
|
13
|
+
def on_complete(env)
|
14
|
+
super
|
15
|
+
rescue Faraday::Error::ResourceNotFound => msg
|
16
|
+
raise ResourceNotFound, msg
|
17
|
+
rescue Faraday::Error::ClientError => msg
|
18
|
+
raise ClientError, msg
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/zeppelin/version.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zeppelin::Middleware::JsonParser do
|
4
|
+
let(:json_body) { "{\"foo\":\"bar\"}" }
|
5
|
+
|
6
|
+
let(:expected_parsed_body) { { 'foo' => 'bar' } }
|
7
|
+
|
8
|
+
it 'parses a standard JSON content type' do
|
9
|
+
process(json_body, 'application/json').body.should eq(expected_parsed_body)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'parses vendor JSON content type' do
|
13
|
+
process(json_body, 'application/vnd.urbanairship+json').body.should eq(expected_parsed_body)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not change nil body' do
|
17
|
+
process(nil).body.should be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'does not parse non-JSON content types' do
|
21
|
+
process('<hello>world</hello>', 'text/xml').body.should eq('<hello>world</hello>')
|
22
|
+
end
|
23
|
+
|
24
|
+
def process(body, content_type=nil, options={})
|
25
|
+
env = { :body => body, :response_headers => Faraday::Utils::Headers.new }
|
26
|
+
env[:response_headers]['content-type'] = content_type if content_type
|
27
|
+
|
28
|
+
middleware = Zeppelin::Middleware::JsonParser.new(
|
29
|
+
lambda { |env| Faraday::Response.new(env) }
|
30
|
+
)
|
31
|
+
|
32
|
+
middleware.call(env)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zeppelin::Middleware::ResponseRaiseError do
|
4
|
+
subject do
|
5
|
+
Faraday.new do |b|
|
6
|
+
b.use(described_class)
|
7
|
+
b.adapter :test do |stub|
|
8
|
+
stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, '<body></body>'] }
|
9
|
+
stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
|
10
|
+
stub.get('error') { [500, { 'X-Error' => 'bailout' }, 'fail' ] }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'does nothing when the response is successful' do
|
16
|
+
expect {
|
17
|
+
subject.get('ok')
|
18
|
+
}.to_not raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises an error when the resource was not found' do
|
22
|
+
expect {
|
23
|
+
subject.get('not-found')
|
24
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises an error when a client error occurs' do
|
28
|
+
expect {
|
29
|
+
subject.get('error')
|
30
|
+
}.to raise_error(Zeppelin::ClientError)
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,470 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zeppelin do
|
4
|
+
let(:device_token) { '1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF' }
|
5
|
+
|
6
|
+
let(:app_key) { 'app key' }
|
7
|
+
|
8
|
+
let(:master_secret) { 'app master secret' }
|
9
|
+
|
10
|
+
let(:options) { { :ssl => { :ca_path => '/dev/null' } } }
|
11
|
+
|
12
|
+
subject { Zeppelin.new(app_key, master_secret, options) }
|
13
|
+
|
14
|
+
describe '.new' do
|
15
|
+
its(:application_key) { should eq(app_key) }
|
16
|
+
|
17
|
+
its(:application_master_secret) { should eq(master_secret) }
|
18
|
+
|
19
|
+
its(:options) { should eq(options) }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#connection' do
|
23
|
+
it { subject.connection.should be_a(Faraday::Connection) }
|
24
|
+
|
25
|
+
it { subject.connection.scheme.should eq('https') }
|
26
|
+
|
27
|
+
it { subject.connection.host.should eq('go.urbanairship.com') }
|
28
|
+
|
29
|
+
it { subject.connection.builder.handlers.should include(Faraday::Adapter::NetHttp) }
|
30
|
+
|
31
|
+
it { subject.connection.builder.handlers.should include(Faraday::Request::JSON) }
|
32
|
+
|
33
|
+
it { subject.connection.builder.handlers.should include(Zeppelin::Middleware::JsonParser) }
|
34
|
+
|
35
|
+
it { subject.connection.builder.handlers.should include(Zeppelin::Middleware::ResponseRaiseError) }
|
36
|
+
|
37
|
+
it { subject.connection.headers['Authorization'].should eq('Basic YXBwIGtleTphcHAgbWFzdGVyIHNlY3JldA==') }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#register_device_token' do
|
41
|
+
let(:payload) { { :alias => 'CapnKernul' } }
|
42
|
+
|
43
|
+
it 'registers a device with the service' do
|
44
|
+
stub_requests do |stub|
|
45
|
+
stub.put("/api/device_tokens/#{device_token}") do |stub|
|
46
|
+
[201, {}, '']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
subject.register_device_token(device_token).should be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'accepts a payload' do
|
54
|
+
stub_requests do |stub|
|
55
|
+
stub.put("/api/device_tokens/#{device_token}", MultiJson.encode(payload)) do
|
56
|
+
[200, {}, '']
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
subject.register_device_token(device_token, payload).should be_true
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'responds with false when an error occurs' do
|
64
|
+
stub_requests do |stub|
|
65
|
+
stub.put("/api/device_tokens/#{device_token}", nil) do
|
66
|
+
[500, {}, '']
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
expect {
|
71
|
+
subject.register_device_token(device_token)
|
72
|
+
}.to raise_error(Zeppelin::ClientError)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#device_token' do
|
77
|
+
let(:response_body) { { 'foo' => 'bar' } }
|
78
|
+
|
79
|
+
it 'gets information about a device' do
|
80
|
+
stub_requests do |stub|
|
81
|
+
stub.get("/api/device_tokens/#{device_token}") do
|
82
|
+
[200, { 'Content-Type' => 'application/json' }, MultiJson.encode(response_body)]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
subject.device_token(device_token).should eq(response_body)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'is nil when the request fails' do
|
90
|
+
stub_requests do |stub|
|
91
|
+
stub.get("/api/device_tokens/#{device_token}") do
|
92
|
+
[404, {}, '']
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
expect {
|
97
|
+
subject.device_token(device_token)
|
98
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#delete_device_token' do
|
103
|
+
it 'is true when successful' do
|
104
|
+
stub_requests do |stub|
|
105
|
+
stub.delete("/api/device_tokens/#{device_token}") do
|
106
|
+
[204, {}, '']
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
subject.delete_device_token(device_token).should be_true
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'is false when the request fails' do
|
114
|
+
stub_requests do |stub|
|
115
|
+
stub.delete("/api/device_tokens/#{device_token}") do
|
116
|
+
[404, {}, '']
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
expect {
|
121
|
+
subject.delete_device_token(device_token)
|
122
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#register_apid' do
|
127
|
+
let(:payload) { { :alias => 'CapnKernul' } }
|
128
|
+
|
129
|
+
it 'registers a device with the service' do
|
130
|
+
stub_requests do |stub|
|
131
|
+
stub.put("/api/apids/#{device_token}") do |stub|
|
132
|
+
[201, {}, '']
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
subject.register_apid(device_token).should be_true
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'accepts a payload' do
|
140
|
+
stub_requests do |stub|
|
141
|
+
stub.put("/api/apids/#{device_token}", MultiJson.encode(payload)) do
|
142
|
+
[200, {}, '']
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
subject.register_apid(device_token, payload).should be_true
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'responds with false when an error occurs' do
|
150
|
+
stub_requests do |stub|
|
151
|
+
stub.put("/api/apids/#{device_token}", nil) do
|
152
|
+
[500, {}, '']
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
expect {
|
157
|
+
subject.register_apid(device_token)
|
158
|
+
}.to raise_error(Zeppelin::ClientError)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#apid' do
|
163
|
+
let(:response_body) { { 'foo' => 'bar' } }
|
164
|
+
|
165
|
+
it 'responds with information about a device when request is successful' do
|
166
|
+
stub_requests do |stub|
|
167
|
+
stub.get("/api/apids/#{device_token}") do
|
168
|
+
[200, { 'Content-Type' => 'application/json' }, MultiJson.encode(response_body)]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
subject.apid(device_token).should eq(response_body)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'is nil when the request fails' do
|
176
|
+
stub_requests do |stub|
|
177
|
+
stub.get("/api/apids/#{device_token}") do
|
178
|
+
[404, {}, '']
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
expect {
|
183
|
+
subject.apid(device_token)
|
184
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#delete_apid' do
|
189
|
+
it 'responds with true when request successful' do
|
190
|
+
stub_requests do |stub|
|
191
|
+
stub.delete("/api/apids/#{device_token}") do
|
192
|
+
[204, {}, '']
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
subject.delete_apid(device_token).should be_true
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'responds with false when request fails' do
|
200
|
+
stub_requests do |stub|
|
201
|
+
stub.delete("/api/apids/#{device_token}") do
|
202
|
+
[404, {}, '']
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
expect {
|
207
|
+
subject.delete_apid(device_token)
|
208
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#push' do
|
213
|
+
let(:payload) { { :device_tokens => [device_token], :aps => { :alert => 'Hello from Urban Airship!' } } }
|
214
|
+
|
215
|
+
it 'is true when the request is successful' do
|
216
|
+
stub_requests do |stub|
|
217
|
+
stub.post('/api/push/', MultiJson.encode(payload)) do
|
218
|
+
[200, {}, '']
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
subject.push(payload).should be_true
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'is false when the request fails' do
|
226
|
+
stub_requests do |stub|
|
227
|
+
stub.post('/api/push/', '{}') do
|
228
|
+
[400, {}, '']
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
expect {
|
233
|
+
subject.push({})
|
234
|
+
}.to raise_error(Zeppelin::ClientError)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe '#batch_push' do
|
239
|
+
let(:message1) {
|
240
|
+
{
|
241
|
+
:device_tokens => [@device_token],
|
242
|
+
:aps => { :alert => 'Hello from Urban Airship!' }
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
let(:message2) {
|
247
|
+
{
|
248
|
+
:device_tokens => [],
|
249
|
+
:aps => { :alert => 'Yet another hello from Urban Airship!' }
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
let(:payload) { [message1, message2] }
|
254
|
+
|
255
|
+
it 'is true when the request was successful' do
|
256
|
+
stub_requests do |stub|
|
257
|
+
stub.post('/api/push/batch/', MultiJson.encode(payload)) do
|
258
|
+
[200, {}, '']
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
subject.batch_push(message1, message2).should be_true
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'is false when the request fails' do
|
266
|
+
stub_requests do |stub|
|
267
|
+
stub.post('/api/push/batch/', '[{},{}]') do
|
268
|
+
[400, {}, '']
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
expect {
|
273
|
+
subject.batch_push({}, {})
|
274
|
+
}.to raise_error(Zeppelin::ClientError)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe '#broadcast' do
|
279
|
+
let(:payload) { { :aps => { :alert => 'Hello from Urban Airship!' } } }
|
280
|
+
|
281
|
+
it 'is true when the request is successful' do
|
282
|
+
stub_requests do |stub|
|
283
|
+
stub.post('/api/push/broadcast/', MultiJson.encode(payload)) do
|
284
|
+
[200, {}, '']
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
subject.broadcast(payload).should be_true
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'is false when the request fails' do
|
292
|
+
stub_requests do |stub|
|
293
|
+
stub.post('/api/push/broadcast/', '{}') do
|
294
|
+
[400, {}, '']
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
expect {
|
299
|
+
subject.broadcast({})
|
300
|
+
}.to raise_error(Zeppelin::ClientError)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
describe '#feedback' do
|
305
|
+
let(:response_body) { { 'foo' => 'bar' } }
|
306
|
+
|
307
|
+
let(:since) { Time.at(0) }
|
308
|
+
|
309
|
+
it 'is the response body for a successful request' do
|
310
|
+
stub_requests do |stub|
|
311
|
+
stub.get('/api/device_tokens/feedback/?since=1970-01-01T00%3A00%3A00Z') do
|
312
|
+
[200, { 'Content-Type' => 'application/json' }, MultiJson.encode(response_body)]
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
subject.feedback(since)
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'is nil when the request fails' do
|
320
|
+
stub_requests do |stub|
|
321
|
+
stub.get('/api/device_tokens/feedback/?since=1970-01-01T00%3A00%3A00Z') do
|
322
|
+
[400, {}, '']
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
expect {
|
327
|
+
subject.feedback(since)
|
328
|
+
}.to raise_error(Zeppelin::ClientError)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
describe '#modify_device_token_on_tag' do
|
333
|
+
let(:tag_name) { 'jimmy.page' }
|
334
|
+
|
335
|
+
let(:device_token) { 'CAFEBABE' }
|
336
|
+
|
337
|
+
it 'requets to modify device tokens on a tag' do
|
338
|
+
stub_requests do |stub|
|
339
|
+
stub.post("/api/tags/#{tag_name}") do
|
340
|
+
[200, {}, 'OK']
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
subject.modify_device_tokens_on_tag(tag_name, { 'device_tokens' => { 'add' => [device_token] } }).should be
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe '#add_tag' do
|
349
|
+
let(:tag_name) { 'chunky.bacon' }
|
350
|
+
|
351
|
+
it 'is true when the request is successful' do
|
352
|
+
stub_requests do |stub|
|
353
|
+
stub.put("/api/tags/#{tag_name}") do
|
354
|
+
[201, {}, '']
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
subject.add_tag(tag_name).should be_true
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
describe '#remove_tag' do
|
363
|
+
let(:tag_name) { 'cats.pajamas' }
|
364
|
+
|
365
|
+
it 'is true when the request is successful' do
|
366
|
+
stub_requests do |stub|
|
367
|
+
stub.delete("/api/tags/#{tag_name}") do
|
368
|
+
[204, {}, '']
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
subject.remove_tag(tag_name).should be_true
|
373
|
+
end
|
374
|
+
|
375
|
+
it 'is false when the request fails' do
|
376
|
+
stub_requests do |stub|
|
377
|
+
stub.delete("/api/tags/#{tag_name}") do
|
378
|
+
[404, {}, '']
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
expect {
|
383
|
+
subject.remove_tag(tag_name)
|
384
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
describe '#device_tags' do
|
389
|
+
let(:response_body) { { 'tags' => ['tag1', 'some_tag'] } }
|
390
|
+
|
391
|
+
it 'is the collection of tags on a device when request is successful' do
|
392
|
+
stub_requests do |stub|
|
393
|
+
stub.get("/api/device_tokens/#{device_token}/tags/") do
|
394
|
+
[200, { 'Content-Type' => 'application/json' }, MultiJson.encode(response_body)]
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
subject.device_tags(device_token).should eq(response_body)
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'is nil when the request fails' do
|
402
|
+
stub_requests do |stub|
|
403
|
+
stub.get("/api/device_tokens/#{device_token}/tags/") do
|
404
|
+
[404, {}, 'Not Found']
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
expect {
|
409
|
+
subject.device_tags(device_token)
|
410
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
describe '#add_tag_to_device' do
|
415
|
+
let(:tag_name) { 'radio.head' }
|
416
|
+
|
417
|
+
it 'is true when the request is successful' do
|
418
|
+
stub_requests do |stub|
|
419
|
+
stub.put("/api/device_tokens/#{device_token}/tags/#{tag_name}") do
|
420
|
+
[201, {}, 'Created']
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
subject.add_tag_to_device(device_token, tag_name).should be_true
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'is false when the request fails' do
|
428
|
+
stub_requests do |stub|
|
429
|
+
stub.put("/api/device_tokens/#{device_token}/tags/#{tag_name}") do
|
430
|
+
[404, {}, '']
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
expect {
|
435
|
+
subject.add_tag_to_device(device_token, tag_name)
|
436
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
describe '#remove_tag_from_device' do
|
441
|
+
let(:tag_name) { 'martin.fowler' }
|
442
|
+
|
443
|
+
it 'is true when the request is successful' do
|
444
|
+
stub_requests do |stub|
|
445
|
+
stub.delete("/api/device_tokens/#{device_token}/tags/#{tag_name}") do
|
446
|
+
[204, {}, 'No Content']
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
subject.remove_tag_from_device(device_token, tag_name).should be_true
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'is false when the request fails' do
|
454
|
+
stub_requests do |stub|
|
455
|
+
stub.delete("/api/device_tokens/#{device_token}/tags/#{tag_name}") do
|
456
|
+
[404, {}, '']
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
expect {
|
461
|
+
subject.remove_tag_from_device(device_token, tag_name)
|
462
|
+
}.to raise_error(Zeppelin::ResourceNotFound)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def stub_requests(&block)
|
467
|
+
subject.connection.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
468
|
+
subject.connection.adapter(:test, &block)
|
469
|
+
end
|
470
|
+
end
|