tddium_client 0.0.5 → 0.0.6
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/lib/tddium_client.rb +59 -60
- data/lib/tddium_client/version.rb +1 -1
- data/spec/tddium_client_spec.rb +184 -124
- metadata +2 -2
data/lib/tddium_client.rb
CHANGED
@@ -10,73 +10,82 @@ module TddiumClient
|
|
10
10
|
API_KEY_HEADER = "X-tddium-api-key"
|
11
11
|
API_ERROR_TEXT = "An error occured: "
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
module Error
|
14
|
+
class Base < RuntimeError; end
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
module Result
|
18
|
+
class Base < Error::Base
|
19
|
+
attr_accessor :http_response
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
def initialize(http_response)
|
22
|
+
self.http_response = http_response
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
25
|
+
def http_code
|
26
|
+
http_response.code
|
27
|
+
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
def http_message
|
30
|
+
http_response.response.header.msg.to_s
|
31
|
+
end
|
29
32
|
end
|
30
33
|
|
31
|
-
|
32
|
-
|
34
|
+
class Abstract < Base
|
35
|
+
attr_accessor :tddium_response
|
36
|
+
|
37
|
+
def initialize(http_response)
|
38
|
+
super
|
39
|
+
self.tddium_response = JSON.parse(http_response.body) rescue {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def [](value)
|
43
|
+
tddium_response[value]
|
44
|
+
end
|
33
45
|
end
|
34
46
|
|
35
|
-
|
36
|
-
|
47
|
+
class API < Abstract
|
48
|
+
def initialize(http_response)
|
49
|
+
super
|
50
|
+
raise TddiumClient::Error::Server.new(http_response) unless tddium_response.include?("status")
|
51
|
+
raise TddiumClient::Error::API.new(http_response) unless tddium_response["status"] == 0
|
52
|
+
end
|
37
53
|
end
|
38
54
|
end
|
39
55
|
|
40
|
-
|
41
|
-
|
56
|
+
module Error
|
57
|
+
class Timeout < Base; end
|
42
58
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def to_s
|
49
|
-
"#{http_code} #{http_result}"
|
50
|
-
end
|
59
|
+
class Server < TddiumClient::Result::Base
|
60
|
+
def to_s
|
61
|
+
"#{http_code} #{http_message}"
|
62
|
+
end
|
51
63
|
|
52
|
-
|
53
|
-
|
64
|
+
def message
|
65
|
+
"Server Error: #{to_s}"
|
66
|
+
end
|
54
67
|
end
|
55
|
-
end
|
56
68
|
|
57
|
-
|
58
|
-
|
69
|
+
class API < TddiumClient::Result::Abstract
|
70
|
+
def initialize(http_response)
|
71
|
+
super
|
72
|
+
end
|
59
73
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
self.response = response
|
64
|
-
end
|
74
|
+
def to_s
|
75
|
+
"#{http_code} #{http_message} (#{status}) #{explanation}"
|
76
|
+
end
|
65
77
|
|
66
|
-
|
67
|
-
|
68
|
-
|
78
|
+
def message
|
79
|
+
"API Error: #{to_s}"
|
80
|
+
end
|
69
81
|
|
70
|
-
|
71
|
-
|
72
|
-
|
82
|
+
def explanation
|
83
|
+
tddium_response["explanation"]
|
84
|
+
end
|
73
85
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def explanation
|
79
|
-
has_response? ? response["explanation"] : nil
|
86
|
+
def status
|
87
|
+
tddium_response["status"]
|
88
|
+
end
|
80
89
|
end
|
81
90
|
end
|
82
91
|
|
@@ -110,19 +119,9 @@ module TddiumClient
|
|
110
119
|
end
|
111
120
|
end
|
112
121
|
|
113
|
-
raise
|
114
|
-
|
115
|
-
response = JSON.parse(http.body) rescue {}
|
116
|
-
|
117
|
-
http_message = http.response.header.msg.to_s
|
118
|
-
|
119
|
-
raise ServerError.new(http.code, http_message) unless response.is_a?(Hash) && response.include?("status")
|
120
|
-
|
121
|
-
result = Result.new(http.code, http.response.header.msg.to_s, response)
|
122
|
-
|
123
|
-
raise APIError.new(result) if !result.success?
|
122
|
+
raise Error::Timeout if tries > retries && retries >= 0
|
124
123
|
|
125
|
-
|
124
|
+
Result::API.new(http)
|
126
125
|
end
|
127
126
|
|
128
127
|
private
|
data/spec/tddium_client_spec.rb
CHANGED
@@ -4,69 +4,199 @@ Copyright (c) 2011 Solano Labs All Rights Reserved
|
|
4
4
|
|
5
5
|
require "spec_helper"
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
describe "TddiumClient" do
|
8
|
+
let(:http_response) { mock(Net::HTTP).as_null_object }
|
9
|
+
|
10
|
+
def stub_sample_api_response(options = {})
|
11
|
+
options[:status]
|
12
|
+
return_value = ""
|
13
|
+
unless options[:status] == false
|
14
|
+
options[:success] = true unless options[:success] == false
|
15
|
+
return_value = {"status" => options[:success] ? 0 : 1}
|
16
|
+
return_value.merge!(:explanation => options[:explanation] || "User not found") unless options[:success]
|
17
|
+
return_value = return_value.to_json
|
18
|
+
end
|
19
|
+
http_response.stub(:body).and_return(return_value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def stub_http_code(code = "401")
|
23
|
+
http_response.stub(:code).and_return(code)
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub_http_message(message = "Unauthorized")
|
27
|
+
http_response.stub_chain(:response, :header, :msg).and_return(message)
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "Response" do
|
31
|
+
|
32
|
+
shared_examples_for "base" do
|
33
|
+
describe "#http_code" do
|
34
|
+
before {stub_http_code("200")}
|
35
|
+
it "should return the http status code from the response" do
|
36
|
+
base.http_code.should == "200"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#http_message" do
|
41
|
+
before {stub_http_message("OK")}
|
42
|
+
it "should return the http message from the response" do
|
43
|
+
base.http_message.should == "OK"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#http_response" do
|
48
|
+
it "should return the http response" do
|
49
|
+
base.http_response.should == http_response
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
shared_examples_for "abstract" do
|
55
|
+
it_should_behave_like "base" do
|
56
|
+
let(:base) { TddiumClient::Result::API.new(http_response) }
|
57
|
+
end
|
58
|
+
|
59
|
+
before { stub_sample_api_response }
|
60
|
+
|
61
|
+
describe "#tddium_response" do
|
62
|
+
it "should return the parsed tddium_response" do
|
63
|
+
abstract.tddium_response.should == {"status" => 0}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#[]" do
|
68
|
+
it "should return the result from the tddium_response" do
|
69
|
+
abstract["status"].should == 0
|
70
|
+
end
|
13
71
|
end
|
72
|
+
end
|
14
73
|
|
15
|
-
|
16
|
-
|
17
|
-
|
74
|
+
describe "Base" do
|
75
|
+
it_should_behave_like "base" do
|
76
|
+
let(:base) {TddiumClient::Result::Base.new(http_response)}
|
18
77
|
end
|
78
|
+
end
|
19
79
|
|
20
|
-
|
21
|
-
|
22
|
-
|
80
|
+
describe "Abstract" do
|
81
|
+
it_should_behave_like "abstract" do
|
82
|
+
let(:abstract) { TddiumClient::Result::Abstract.new(http_response) }
|
23
83
|
end
|
24
84
|
end
|
25
85
|
|
26
|
-
describe "
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
86
|
+
describe "API" do
|
87
|
+
let(:api) { TddiumClient::Result::API.new(http_response) }
|
88
|
+
it_should_behave_like "abstract" do
|
89
|
+
let(:abstract) { api }
|
90
|
+
end
|
91
|
+
|
92
|
+
context "no status is included in the response" do
|
93
|
+
before {stub_sample_api_response(:status => false) }
|
94
|
+
|
95
|
+
it "should raise a ServerError" do
|
96
|
+
expect {
|
97
|
+
TddiumClient::Result::API.new(http_response)
|
98
|
+
}.to raise_error(TddiumClient::Error::Server)
|
31
99
|
end
|
32
100
|
end
|
33
101
|
|
34
|
-
context "
|
35
|
-
|
36
|
-
|
37
|
-
|
102
|
+
context "a status is included in the response but it does not == 0" do
|
103
|
+
before {stub_sample_api_response(:success => false) }
|
104
|
+
|
105
|
+
it "should raise an APIError" do
|
106
|
+
expect {
|
107
|
+
TddiumClient::Result::API.new(http_response)
|
108
|
+
}.to raise_error(TddiumClient::Error::API)
|
38
109
|
end
|
110
|
+
end
|
39
111
|
|
40
|
-
|
41
|
-
|
42
|
-
|
112
|
+
context "a status is included in the response and it == 0" do
|
113
|
+
before {stub_sample_api_response }
|
114
|
+
it "should return a new instance of Response::Client" do
|
115
|
+
TddiumClient::Result::API.new(http_response).should be_a(TddiumClient::Result::API)
|
43
116
|
end
|
44
117
|
end
|
45
118
|
end
|
46
119
|
end
|
47
120
|
|
48
|
-
describe
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
121
|
+
describe "Error" do
|
122
|
+
shared_examples_for "#to_s" do
|
123
|
+
before do
|
124
|
+
stub_http_code("401")
|
125
|
+
stub_http_message("Unauthorized")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should contain the http code" do
|
129
|
+
result.should include("401")
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should contain the http message" do
|
133
|
+
result.should include("Unauthorized")
|
134
|
+
end
|
55
135
|
end
|
56
|
-
end
|
57
136
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
137
|
+
describe "Server" do
|
138
|
+
let(:server_error) { TddiumClient::Error::Server.new(http_response) }
|
139
|
+
|
140
|
+
it_should_behave_like("base") do
|
141
|
+
let(:base) { server_error }
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "#to_s" do
|
145
|
+
it_should_behave_like("#to_s") do
|
146
|
+
let(:result) {server_error.to_s}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "#message" do
|
151
|
+
it_should_behave_like("#to_s") do
|
152
|
+
let(:result) {server_error.message}
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should start with 'Server Error:'" do
|
156
|
+
server_error.message.should =~ /^Server Error:/
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "API" do
|
162
|
+
let(:api_error) { TddiumClient::Error::API.new(http_response) }
|
163
|
+
|
164
|
+
it_should_behave_like("abstract") do
|
165
|
+
let(:abstract) { api_error }
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#to_s" do
|
169
|
+
it_should_behave_like("#to_s") do
|
170
|
+
let(:result) {api_error.to_s}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#message" do
|
175
|
+
before do
|
176
|
+
stub_sample_api_response(:success => false, :explanation => "User is invalid")
|
177
|
+
end
|
178
|
+
|
179
|
+
it_should_behave_like("#to_s") do
|
180
|
+
let(:result) {api_error.message}
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should start with 'API Error:'" do
|
184
|
+
api_error.message.should =~ /^API Error:/
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should include the api status in brackets ()" do
|
188
|
+
api_error.message.should include("(1)")
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should include the api explanation" do
|
192
|
+
api_error.message.should include("User is invalid")
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
66
196
|
end
|
67
197
|
end
|
68
198
|
|
69
|
-
describe Client do
|
199
|
+
describe "Client" do
|
70
200
|
include FakeFS::SpecHelpers
|
71
201
|
include TddiumSpecHelpers
|
72
202
|
|
@@ -105,7 +235,7 @@ module TddiumClient
|
|
105
235
|
end
|
106
236
|
|
107
237
|
describe "#call_api" do
|
108
|
-
before
|
238
|
+
before do
|
109
239
|
FakeWeb.clean_registry
|
110
240
|
stub_tddium_client_config
|
111
241
|
stub_http_response(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, :response => fixture_path("post_suites_201.json"))
|
@@ -130,12 +260,12 @@ module TddiumClient
|
|
130
260
|
|
131
261
|
it "should retry 5 times by default to contact the API" do
|
132
262
|
HTTParty.should_receive(EXAMPLE_HTTP_METHOD).exactly(6).times
|
133
|
-
expect { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE) }.to raise_error(TddiumClient::
|
263
|
+
expect { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE) }.to raise_error(TddiumClient::Error::Timeout)
|
134
264
|
end
|
135
265
|
|
136
266
|
it "should retry as many times as we want to contact the API" do
|
137
267
|
HTTParty.should_receive(EXAMPLE_HTTP_METHOD).exactly(3).times
|
138
|
-
expect { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, {}, nil, 2) }.to raise_error(TddiumClient::
|
268
|
+
expect { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, {}, nil, 2) }.to raise_error(TddiumClient::Error::Timeout)
|
139
269
|
end
|
140
270
|
end
|
141
271
|
|
@@ -177,102 +307,32 @@ module TddiumClient
|
|
177
307
|
tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, {}, nil) rescue {}
|
178
308
|
end
|
179
309
|
|
180
|
-
it "should return a TddiumClient::Result" do
|
310
|
+
it "should return a TddiumClient::Result::Client" do
|
181
311
|
result = tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, {}, nil)
|
182
|
-
result.should be_a(TddiumClient::Result)
|
312
|
+
result.should be_a(TddiumClient::Result::API)
|
183
313
|
end
|
184
314
|
|
185
315
|
it "should parse the JSON response" do
|
186
316
|
result = tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, {}, nil)
|
187
|
-
result.
|
188
|
-
result.
|
189
|
-
result.response["status"].should == 0
|
190
|
-
result.should be_success
|
191
|
-
result.response["suite"]["id"].should == 19
|
317
|
+
result.tddium_response["status"].should == 0
|
318
|
+
result.tddium_response["suite"]["id"].should == 19
|
192
319
|
end
|
193
320
|
end
|
194
321
|
|
195
|
-
context "
|
322
|
+
context "the response has no 'status' in the body" do
|
196
323
|
before { stub_http_response(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, :status => ["501", "Internal Server Error"]) }
|
197
|
-
it "should raise a TddiumClient::
|
198
|
-
expect
|
324
|
+
it "should raise a TddiumClient::Error::Server" do
|
325
|
+
expect {
|
199
326
|
tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE)
|
200
|
-
|
201
|
-
puts error.inspect
|
202
|
-
error.should be_a(TddiumClient::ServerError)
|
203
|
-
error.should respond_to(:http_code)
|
204
|
-
error.http_code.should == 500
|
205
|
-
error.http_message.should =~ /Internal Server Error/
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
context "when no response is present" do
|
210
|
-
before { stub_http_response(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, :status => ["200", "OK"]) }
|
211
|
-
it "should raise a TddiumClient::ServerError" do
|
212
|
-
expect do
|
213
|
-
tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE)
|
214
|
-
end.to raise_error do |error|
|
215
|
-
error.should be_a(TddiumClient::ServerError)
|
216
|
-
error.should respond_to(:http_code)
|
217
|
-
error.http_code.should == 200
|
218
|
-
error.http_message.should =~ /OK/
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
shared_examples_for "raising an APIError" do
|
225
|
-
# users can set:
|
226
|
-
#
|
227
|
-
# aproc
|
228
|
-
# http_code
|
229
|
-
# http_message
|
230
|
-
it "should raise the right exception" do
|
231
|
-
expect { aproc.call }.to raise_error do |error|
|
232
|
-
error.should be_a(TddiumClient::APIError)
|
233
|
-
error.should respond_to(:tddium_result)
|
234
|
-
error.tddium_result.should be_a(TddiumClient::Result)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
it "should capture the http response line" do
|
239
|
-
expect { aproc.call }.to raise_error do |error|
|
240
|
-
error.tddium_result.http_code.should == http_code if http_code
|
241
|
-
error.tddium_result.http_message.should == http_message if http_message
|
242
|
-
end
|
327
|
+
}.to raise_error(TddiumClient::Error::Server)
|
243
328
|
end
|
244
329
|
end
|
245
330
|
|
246
331
|
context "where the http request was successful but API status is not 0" do
|
247
332
|
before { stub_http_response(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, :response => fixture_path("post_suites_269_json_status_1.json")) }
|
248
333
|
|
249
|
-
|
250
|
-
|
251
|
-
let(:http_code) {269}
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
context "exceptions for an error response" do
|
256
|
-
before { stub_http_response(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, :status => ["404", "Not Found"]) }
|
257
|
-
it_should_behave_like "raising an APIError" do
|
258
|
-
let(:aproc) { Proc.new { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE) } }
|
259
|
-
let(:http_code) {404}
|
260
|
-
end
|
261
|
-
|
262
|
-
context "and an API error is returned" do
|
263
|
-
before { stub_http_response(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE, :response => fixture_path("post_suites_409.json")) }
|
264
|
-
it_should_behave_like "raising an APIError" do
|
265
|
-
let(:aproc) { Proc.new { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE) } }
|
266
|
-
let(:http_code) {409}
|
267
|
-
end
|
268
|
-
|
269
|
-
it "should have an api status" do
|
270
|
-
expect do
|
271
|
-
tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE)
|
272
|
-
end.to raise_error do |error|
|
273
|
-
error.tddium_result.response[:status].should == 1
|
274
|
-
end
|
275
|
-
end
|
334
|
+
it "should raise a TddiumClient::Error::API Error" do
|
335
|
+
expect { tddium_client.call_api(EXAMPLE_HTTP_METHOD, EXAMPLE_TDDIUM_RESOURCE) }.to raise_error(TddiumClient::Error::API)
|
276
336
|
end
|
277
337
|
end
|
278
338
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: tddium_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jay Moorthi
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-04-04 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|