hover-ruby-client 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ require 'active_support/concern'
2
+ require 'hover/client/hover'
3
+
4
+ module Hover
5
+ module Jobs
6
+ module Concerns
7
+ module RetryNetworkErrors
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ @backoff_strategy = [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60, 120, 240, 480]
12
+
13
+ # http://ruby-doc.org/stdlib-1.9.2/libdoc/socket/rdoc/Socket.html
14
+
15
+ @retry_exceptions = [
16
+ Hover::Client::Unavailable,
17
+ Timeout::Error,
18
+ Net::ProtocolError,
19
+ Errno::ECONNRESET,
20
+ Errno::ECONNREFUSED,
21
+ Errno::EALREADY,
22
+ Errno::EFAULT,
23
+ Errno::EHOSTUNREACH,
24
+ Errno::EINPROGRESS,
25
+ Errno::EINTR,
26
+ Errno::EISCONN,
27
+ Errno::EINVAL,
28
+ Errno::ENETDOWN,
29
+ Errno::ENETUNREACH,
30
+ Errno::ENOBUFS,
31
+ Errno::ENOSR,
32
+ Errno::EOPNOTSUPP,
33
+ Errno::ETIMEDOUT
34
+ ]
35
+
36
+ #
37
+ # make sure this comes after the variables above ^
38
+ #
39
+ extend Resque::Plugins::ExponentialBackoff if defined?(Resque::Plugins::ExponentialBackoff)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Hover
2
+ VERSION = "0.3.1"
3
+ end
@@ -0,0 +1 @@
1
+ source 'https://rubygems.org'
Binary file
@@ -0,0 +1,106 @@
1
+ {"id":6,"image":null,"item_id":null,"a":null,"class":"TestClass"}
2
+ {"id":7,"image":null,"item_id":null,"a":null,"class":"TestClass"}
3
+ {"id":8,"image":null,"item_id":null,"a":null,"class":"TestClass"}
4
+ {"id":9,"image":null,"item_id":null,"a":null,"class":"TestClass"}
5
+ {"id":10,"image":null,"item_id":null,"a":null,"class":"TestClass"}
6
+ {"id":11,"image":null,"item_id":null,"a":null,"class":"TestClass"}
7
+ {"id":12,"image":null,"item_id":null,"a":null,"class":"TestClass"}
8
+ {"id":13,"image":null,"item_id":null,"a":null,"class":"TestClass"}
9
+ {"id":14,"image":null,"item_id":null,"a":null,"class":"TestClass"}
10
+ {"id":15,"image":null,"item_id":null,"a":null,"class":"TestClass"}
11
+ {"id":16,"image":null,"item_id":null,"a":null,"class":"TestClass"}
12
+ {"id":17,"image":null,"item_id":null,"a":null,"class":"TestClass"}
13
+ {"id":18,"image":null,"item_id":null,"a":null,"class":"TestClass"}
14
+ {"id":19,"image":null,"item_id":null,"a":null,"class":"TestClass"}
15
+ {"id":20,"image":null,"item_id":null,"a":null,"class":"TestClass"}
16
+ {"id":21,"image":null,"item_id":null,"a":null,"class":"TestClass"}
17
+ {"id":22,"image":null,"item_id":null,"a":null,"class":"TestClass"}
18
+ {"id":23,"image":null,"item_id":null,"a":null,"class":"TestClass"}
19
+ {"id":24,"image":null,"item_id":null,"a":null,"class":"TestClass"}
20
+ {"id":25,"image":null,"item_id":null,"a":null,"class":"TestClass"}
21
+ {"id":26,"image":null,"item_id":null,"a":null,"class":"TestClass"}
22
+ {"id":27,"image":null,"item_id":null,"a":null,"class":"TestClass"}
23
+ {"id":28,"image":null,"item_id":null,"a":null,"class":"TestClass"}
24
+ {"id":29,"image":null,"item_id":null,"a":null,"class":"TestClass"}
25
+ {"id":30,"image":null,"item_id":null,"a":null,"class":"TestClass"}
26
+ {"id":31,"image":null,"item_id":null,"a":null,"class":"TestClass"}
27
+ {"id":32,"image":null,"item_id":null,"a":null,"class":"TestClass"}
28
+ {"id":33,"image":null,"item_id":null,"a":null,"class":"TestClass"}
29
+ {"id":34,"image":null,"item_id":null,"a":null,"class":"TestClass"}
30
+ {"id":35,"image":null,"item_id":null,"a":null,"class":"TestClass"}
31
+ {"id":36,"image":null,"item_id":null,"a":null,"class":"TestClass"}
32
+ {"id":37,"image":null,"item_id":null,"a":null,"class":"TestClass"}
33
+ {"id":38,"image":null,"item_id":null,"a":null,"class":"TestClass"}
34
+ {"id":39,"image":null,"item_id":null,"a":null,"class":"TestClass"}
35
+ {"id":40,"image":null,"item_id":null,"a":null,"class":"TestClass"}
36
+ {"id":41,"image":null,"item_id":null,"a":null,"class":"TestClass"}
37
+ {"id":42,"image":null,"item_id":null,"a":null,"class":"TestClass"}
38
+ {"id":43,"image":null,"item_id":null,"a":null,"class":"TestClass"}
39
+ {"id":44,"image":null,"item_id":null,"a":null,"class":"TestClass"}
40
+ {"id":45,"image":null,"item_id":null,"a":null,"class":"TestClass"}
41
+ {"id":46,"image":null,"item_id":null,"a":null,"class":"TestClass"}
42
+ {"id":47,"image":null,"item_id":null,"a":null,"class":"TestClass"}
43
+ {"id":48,"image":null,"item_id":null,"a":null,"class":"TestClass"}
44
+ {"id":49,"image":null,"item_id":null,"a":null,"class":"TestClass"}
45
+ {"id":50,"image":null,"item_id":null,"a":null,"class":"TestClass"}
46
+ {"id":51,"image":null,"item_id":null,"a":null,"class":"TestClass"}
47
+ {"id":52,"image":null,"item_id":null,"a":null,"class":"TestClass"}
48
+ {"id":53,"image":null,"item_id":null,"a":null,"class":"TestClass"}
49
+ {"id":54,"image":null,"item_id":null,"a":null,"class":"TestClass"}
50
+ {"id":55,"image":null,"item_id":null,"a":null,"class":"TestClass"}
51
+ {"id":56,"image":null,"item_id":null,"a":null,"class":"TestClass"}
52
+ {"id":57,"image":null,"item_id":null,"a":null,"class":"TestClass"}
53
+ {"id":1,"taggable_id":1,"taggable_type":"Item","name":"tag","class":"Tag"}
54
+ {"id":2,"taggable_id":1,"taggable_type":"Item","name":"tag","class":"Tag"}
55
+ {"id":3,"taggable_id":1,"taggable_type":"Item","name":"tag","class":"Tag"}
56
+ {"id":4,"taggable_id":2,"taggable_type":"Item","name":"tag","class":"Tag"}
57
+ {"id":5,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
58
+ {"id":6,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
59
+ {"id":7,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
60
+ {"id":8,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
61
+ {"id":9,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
62
+ {"id":10,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
63
+ {"id":11,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
64
+ {"id":12,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
65
+ {"id":13,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
66
+ {"id":14,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
67
+ {"id":15,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
68
+ {"id":16,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
69
+ {"id":17,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
70
+ {"id":18,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
71
+ {"id":19,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
72
+ {"id":20,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
73
+ {"id":21,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
74
+ {"id":22,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
75
+ {"id":23,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
76
+ {"id":24,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
77
+ {"id":25,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
78
+ {"id":26,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
79
+ {"id":27,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
80
+ {"id":28,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
81
+ {"id":29,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
82
+ {"id":30,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
83
+ {"id":31,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
84
+ {"id":32,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
85
+ {"id":33,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
86
+ {"id":34,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
87
+ {"id":35,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
88
+ {"id":36,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
89
+ {"id":37,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
90
+ {"id":38,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
91
+ {"id":39,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
92
+ {"id":40,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
93
+ {"id":41,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
94
+ {"id":42,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
95
+ {"id":43,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
96
+ {"id":44,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
97
+ {"id":45,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
98
+ {"id":46,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
99
+ {"id":47,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
100
+ {"id":48,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
101
+ {"id":49,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
102
+ {"id":50,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
103
+ {"id":51,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
104
+ {"id":52,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
105
+ {"id":53,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
106
+ {"id":54,"taggable_id":null,"taggable_type":null,"name":null,"class":"Tag"}
@@ -0,0 +1,80 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+ IS_RAKE_TASK = (!! ($0 =~ /rake/))
3
+
4
+ if IS_RAKE_TASK
5
+ #
6
+ # Code coverage reports
7
+ #
8
+
9
+ require 'coverage'
10
+ require 'simplecov'
11
+ require 'simplecov-rcov'
12
+
13
+ ROOT_DIR = File.expand_path('../..', __FILE__)
14
+
15
+ SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
16
+
17
+ SimpleCov.start do
18
+ minimum_coverage 0
19
+ coverage_dir File.join(File.dirname(__FILE__), 'reports')
20
+ root ROOT_DIR
21
+
22
+ add_filter do |src|
23
+ File.dirname(src.filename) =~ /#{File.join(ROOT_DIR, 'test')}/
24
+ end
25
+ end
26
+ end
27
+
28
+ require 'minitest/autorun'
29
+ require 'minitest/mock'
30
+ require 'mocha/minitest'
31
+ require 'minitest/reporters'
32
+
33
+ reporters = [ Minitest::Reporters::SpecReporter.new ]
34
+
35
+ Minitest::Reporters.use!(reporters)
36
+
37
+
38
+ def index_json_hash(collection, page = 1, per_page = 2)
39
+ {
40
+ "pagination" => {
41
+ "current_page" => page,
42
+ "total_pages" => (collection.size / per_page),
43
+ "total" => collection.size,
44
+ "per_page" => per_page
45
+ },
46
+
47
+ "results" => collection.slice((per_page * (page - 1)), per_page)
48
+ }
49
+ end
50
+
51
+ require 'byebug'
52
+ require 'rails/all'
53
+ require 'active_record'
54
+
55
+ database_path = '/tmp/hover-ruby-client_test.sqlite3'
56
+ FileUtils.rm(database_path) if File.exist?(database_path)
57
+ ActiveRecord::Base.establish_connection({adapter: :sqlite3, database: database_path})
58
+
59
+ ActiveRecord::Schema.define do
60
+ create_table(:test_classes) do |t|
61
+ t.text :image
62
+ t.text :document
63
+ t.integer :item_id
64
+ t.integer :a
65
+ end
66
+
67
+ create_table(:scoped_test_classes) do |t|
68
+ t.integer :item_id
69
+ t.integer :a
70
+ end
71
+
72
+ create_table(:items) do |t|
73
+ end
74
+
75
+ create_table(:tags) do |t|
76
+ t.integer :taggable_id
77
+ t.string :taggable_type
78
+ t.string :name
79
+ end
80
+ end
@@ -0,0 +1,21 @@
1
+ require './test/test_helper'
2
+
3
+ require 'hover/client/basic_auth'
4
+
5
+ describe Hover::Client::BasicAuth do
6
+ let(:client) { Hover::Client::BasicAuth.new('elise@hoverinc.com', 'password') }
7
+ let(:path) { '/testing' }
8
+ let(:request) { mock }
9
+ let(:response) { mock }
10
+
11
+ describe "authenticate" do
12
+ it "authenticate" do
13
+ request = mock
14
+ request.expects(:basic_auth).with('elise@hoverinc.com', 'password')
15
+
16
+ client.authenticate(request)
17
+ end
18
+ end
19
+
20
+
21
+ end
@@ -0,0 +1,277 @@
1
+ require './test/test_helper'
2
+
3
+ require 'hover/client/hmac'
4
+
5
+ describe Hover::Client::HMAC do
6
+ let(:client) { Hover::Client::HMAC.new(1, 2, 'http://localhost') }
7
+ let(:path) { '/testing' }
8
+ let(:request) { mock }
9
+ let(:response) { mock }
10
+
11
+ describe "authenticate" do
12
+ it "authenticate" do
13
+ request = mock
14
+ ApiAuth.expects(:sign!).with(request, 1, 2).once
15
+
16
+ client.authenticate(request)
17
+ end
18
+ end
19
+
20
+ describe "make_uri" do
21
+ it "makes correct uri with parameters" do
22
+ client.make_uri('testing', {a: 1}).to_s.must_equal("http://localhost/api/v1/testing?a=1")
23
+ end
24
+
25
+ it "with parameters" do
26
+ URI.expects(:parse).twice
27
+ URI.expects(:encode_www_form).with({a: 1}).once
28
+
29
+ client.make_uri('testing', {a: 1})
30
+ end
31
+
32
+ it "makes correct uri without parameters" do
33
+ client.make_uri('testing').to_s.must_equal("http://localhost/api/v1/testing")
34
+ end
35
+
36
+ it "without parameters" do
37
+ URI.expects(:parse).once
38
+ Array.any_instance.expects(:join).once.returns('http://localhost/api/v1/testing')
39
+ URI.expects(:encode_www_form).never
40
+
41
+ client.make_uri('testing')
42
+ end
43
+ end
44
+
45
+ describe "make_request" do
46
+ it "requests without ssl" do
47
+ uri = URI('http://localhost/test')
48
+ http = mock
49
+
50
+ http.expects(:request).with(request).returns(response).once
51
+ http.expects(:use_ssl=).never
52
+
53
+ client.expects(:raise_errors_for_cloudfront_response)
54
+ client.expects(:authenticate).with(request).once
55
+ Net::HTTP.expects(:new).with(uri.host, uri.port).returns(http)
56
+
57
+ client.make_request(request, uri).must_equal(response)
58
+ end
59
+
60
+ it 'requests with ssl' do
61
+ uri = URI('https://localhost/test')
62
+ http = mock
63
+
64
+ http.expects(:request).with(request).returns(response).once
65
+ http.expects(:use_ssl=).with(true).once
66
+
67
+ client.expects(:raise_errors_for_cloudfront_response)
68
+ client.expects(:authenticate).with(request).once
69
+ Net::HTTP.expects(:new).with(uri.host, uri.port).returns(http)
70
+
71
+ client.make_request(request, uri).must_equal(response)
72
+ end
73
+ end
74
+
75
+ describe "get" do
76
+ it "gets without parameters" do
77
+ uri = URI("http://localhost/testing")
78
+ Net::HTTP::Get.expects(:new).with(uri).returns(request)
79
+ client.expects(:make_request).with(request, uri).returns(response)
80
+
81
+ client.expects(:make_uri).with(path, {}).once.returns(uri)
82
+
83
+ client.get(path)
84
+ end
85
+
86
+ it "gets with parameters" do
87
+ parameters = {a: 1, b: 2}
88
+ uri = URI("http://localhost/testing?a=1&b=2")
89
+ Net::HTTP::Get.expects(:new).with(uri).returns(request)
90
+ client.expects(:make_request).with(request, uri).returns(response)
91
+
92
+ client.expects(:make_uri).with(path, parameters).once.returns(uri)
93
+
94
+ client.get(path, parameters)
95
+ end
96
+ end
97
+
98
+ describe "get_redirect_location" do
99
+ let(:uri) { URI("http://localhost/testing") }
100
+
101
+ before do
102
+ client.expects(:parse_response).never
103
+
104
+ Net::HTTP::Get.expects(:new).with(uri).returns(request)
105
+ client.expects(:make_request).with(request, uri).returns(response)
106
+ client.expects(:make_uri).with(path, {}).once.returns(uri)
107
+ end
108
+
109
+ it "isn't a redirect response" do
110
+ response.expects(:is_a?).with(Net::HTTPRedirection).returns(false)
111
+ response.expects(:[]).with('location').never
112
+
113
+ assert_nil client.get_redirect_location(path)
114
+ end
115
+
116
+ it "is a redirect response, but no location was given" do
117
+ response.expects(:is_a?).with(Net::HTTPRedirection).returns(true)
118
+ response.expects(:[]).with('location').once.returns(nil)
119
+
120
+ assert_nil client.get_redirect_location(path)
121
+ end
122
+
123
+ it "is a redirect" do
124
+ redirect_location = 'http://location/elsewhere'
125
+
126
+ response.expects(:is_a?).with(Net::HTTPRedirection).returns(true)
127
+ response.expects(:[]).with('location').returns(redirect_location).twice
128
+
129
+ client.get_redirect_location(path).must_equal(redirect_location)
130
+ end
131
+
132
+ end
133
+
134
+ describe "post" do
135
+ it 'posts' do
136
+ path = '/post'
137
+ uri = URI.parse('http://localhost/post')
138
+
139
+ client.expects(:make_uri).with(path).returns(uri).once
140
+ Net::HTTP::Post.expects(:new).with(uri).returns(request)
141
+
142
+ client.expects(:make_request).with(request, uri).returns(response)
143
+ request.expects(:set_form_data).with({}).once
144
+
145
+ client.post(path)
146
+ end
147
+ end
148
+
149
+ describe "put" do
150
+ it 'puts' do
151
+ path = '/put'
152
+ uri = URI.parse('http://localhost/put')
153
+
154
+ client.expects(:make_uri).with(path).returns(uri).once
155
+ Net::HTTP::Put.expects(:new).with(uri).returns(request)
156
+
157
+ client.expects(:make_request).with(request, uri).returns(response)
158
+ request.expects(:set_form_data).with({}).once
159
+
160
+ client.put(path)
161
+ end
162
+ end
163
+
164
+ describe "patch" do
165
+ it 'patch' do
166
+ path = '/patch'
167
+ uri = URI.parse('http://localhost/patch')
168
+
169
+ client.expects(:make_uri).with(path).returns(uri).once
170
+ Net::HTTP::Patch.expects(:new).with(uri).returns(request)
171
+
172
+ client.expects(:make_request).with(request, uri).returns(response)
173
+ request.expects(:set_form_data).with({}).once
174
+
175
+ client.patch(path)
176
+ end
177
+ end
178
+
179
+ describe "delete" do
180
+ it 'delete' do
181
+ path = '/delete'
182
+ uri = URI.parse('http://localhost/delete')
183
+
184
+ client.expects(:make_uri).with(path).returns(uri).once
185
+ Net::HTTP::Delete.expects(:new).with(uri).returns(request)
186
+
187
+ client.expects(:make_request).with(request, uri).returns(response)
188
+ request.expects(:set_form_data).with({}).once
189
+
190
+ client.delete(path)
191
+ end
192
+ end
193
+
194
+ describe "parse_response" do
195
+ let(:response) { mock }
196
+ let(:valid_json) { '{"a": 1}' }
197
+ let(:invalid_json) { '{"a": 1, "b" => 2}' }
198
+
199
+ before do
200
+ client.expects(:raise_errors).with(response).once
201
+ end
202
+
203
+ it "204 no content" do
204
+ response.expects(:code).returns(204)
205
+ response.expects(:body).never
206
+ ::JSON.expects(:parse).never
207
+
208
+ client.parse_response(response)
209
+ end
210
+
211
+ it "valid json" do
212
+ response.expects(:code).returns(200)
213
+ response.expects(:body).returns(valid_json).once
214
+ ::JSON.expects(:parse).with(valid_json)
215
+
216
+ client.parse_response(response)
217
+ end
218
+
219
+ it "invalid json" do
220
+ response.expects(:code).returns(200)
221
+ response.expects(:body).returns(invalid_json).once
222
+ ::JSON.expects(:parse).with(invalid_json)
223
+
224
+ client.parse_response(response)
225
+ end
226
+
227
+ end
228
+
229
+ describe "raise_errors_for_cloudfront_response" do
230
+ let(:header) { mock }
231
+ let(:cloudfront_server) { 'Cloudfront' }
232
+ let(:nginx_server) { 'nginx/1.2.9' }
233
+
234
+ before do
235
+ response.expects(:header).returns(header)
236
+ end
237
+
238
+ it "cloudfront" do
239
+ header.expects(:[]).with('Server').returns(cloudfront_server)
240
+
241
+ ->{ client.raise_errors_for_cloudfront_response(response) }.must_raise(Hover::Client::Unavailable)
242
+ end
243
+
244
+ it "nginx" do
245
+ header.expects(:[]).with('Server').returns(nginx_server)
246
+
247
+ client.raise_errors_for_cloudfront_response(response)
248
+ end
249
+ end
250
+
251
+ describe "raise_errors" do
252
+ before do
253
+ response.expects(:body).once
254
+ end
255
+
256
+ {
257
+ 400 => Hover::Client::BadRequest,
258
+ 401 => Hover::Client::Unauthorized,
259
+ 403 => Hover::Client::General,
260
+ 404 => Hover::Client::NotFound,
261
+ 500 => Hover::Client::InternalError,
262
+ 502 => Hover::Client::Unavailable,
263
+ 503 => Hover::Client::Unavailable
264
+ }.each do |code, exception_class|
265
+ it code.to_s do
266
+ response.expects(:code).returns(code.to_s).twice
267
+
268
+ -> { client.raise_errors(response) }.must_raise(exception_class)
269
+ end
270
+ end
271
+
272
+ it "200" do
273
+ response.expects(:code).returns('200').twice
274
+ client.raise_errors(response)
275
+ end
276
+ end
277
+ end