hops-airborne 0.2.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +38 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +10 -0
- data/LICENSE +9 -0
- data/README.md +429 -0
- data/airborne.gemspec +19 -0
- data/lib/airborne/base.rb +82 -0
- data/lib/airborne/optional_hash_type_expectations.rb +23 -0
- data/lib/airborne/path_matcher.rb +101 -0
- data/lib/airborne/rack_test_requester.rb +18 -0
- data/lib/airborne/request_expectations.rb +285 -0
- data/lib/airborne/rest_client_requester.rb +33 -0
- data/lib/airborne.rb +29 -0
- data/spec/airborne/base_spec.rb +55 -0
- data/spec/airborne/client_requester_spec.rb +42 -0
- data/spec/airborne/delete_spec.rb +9 -0
- data/spec/airborne/expectations/expect_header_contains_spec.rb +21 -0
- data/spec/airborne/expectations/expect_header_spec.rb +21 -0
- data/spec/airborne/expectations/expect_json_keys_path_spec.rb +15 -0
- data/spec/airborne/expectations/expect_json_keys_spec.rb +21 -0
- data/spec/airborne/expectations/expect_json_lambda_spec.rb +9 -0
- data/spec/airborne/expectations/expect_json_options_spec.rb +65 -0
- data/spec/airborne/expectations/expect_json_path_spec.rb +108 -0
- data/spec/airborne/expectations/expect_json_regex_spec.rb +33 -0
- data/spec/airborne/expectations/expect_json_sizes_spec.rb +33 -0
- data/spec/airborne/expectations/expect_json_spec.rb +27 -0
- data/spec/airborne/expectations/expect_json_types_date_spec.rb +52 -0
- data/spec/airborne/expectations/expect_json_types_lambda_spec.rb +9 -0
- data/spec/airborne/expectations/expect_json_types_optional_spec.rb +15 -0
- data/spec/airborne/expectations/expect_json_types_options_spec.rb +59 -0
- data/spec/airborne/expectations/expect_json_types_path_spec.rb +65 -0
- data/spec/airborne/expectations/expect_json_types_spec.rb +85 -0
- data/spec/airborne/expectations/expect_status_spec.rb +23 -0
- data/spec/airborne/head_spec.rb +10 -0
- data/spec/airborne/options_spec.rb +10 -0
- data/spec/airborne/patch_spec.rb +9 -0
- data/spec/airborne/path_spec.rb +34 -0
- data/spec/airborne/post_spec.rb +17 -0
- data/spec/airborne/put_spec.rb +9 -0
- data/spec/airborne/rack/rack_sinatra_spec.rb +43 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/stub_helper.rb +45 -0
- data/spec/test_responses/array_of_types.json +9 -0
- data/spec/test_responses/array_of_values.json +5 -0
- data/spec/test_responses/array_response.json +5 -0
- data/spec/test_responses/array_with_index.json +6 -0
- data/spec/test_responses/array_with_nested.json +16 -0
- data/spec/test_responses/array_with_nested_bad_data.json +15 -0
- data/spec/test_responses/array_with_partial_nested.json +12 -0
- data/spec/test_responses/date_is_null_response.json +3 -0
- data/spec/test_responses/date_response.json +3 -0
- data/spec/test_responses/hash_property.json +3 -0
- data/spec/test_responses/invalid_get.json +1 -0
- data/spec/test_responses/invalid_json.json +1 -0
- data/spec/test_responses/numeric_property.json +6 -0
- data/spec/test_responses/simple_delete.json +4 -0
- data/spec/test_responses/simple_get.json +5 -0
- data/spec/test_responses/simple_json.json +5 -0
- data/spec/test_responses/simple_nested_path.json +12 -0
- data/spec/test_responses/simple_patch.json +4 -0
- data/spec/test_responses/simple_path_get.json +8 -0
- data/spec/test_responses/simple_post.json +4 -0
- data/spec/test_responses/simple_put.json +4 -0
- metadata +206 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
module Airborne
|
2
|
+
class PathError < StandardError; end
|
3
|
+
|
4
|
+
module PathMatcher
|
5
|
+
def get_by_path(path, json, &block)
|
6
|
+
fail PathError, "Invalid Path, contains '..'" if /\.\./ =~ path
|
7
|
+
type = false
|
8
|
+
parts = path.split('.')
|
9
|
+
parts.each_with_index do |part, index|
|
10
|
+
if part == '*' || part == '?'
|
11
|
+
ensure_array(path, json)
|
12
|
+
type = part
|
13
|
+
if index < parts.length.pred
|
14
|
+
walk_with_path(type, index, path, parts, json, &block) && return
|
15
|
+
end
|
16
|
+
next
|
17
|
+
end
|
18
|
+
begin
|
19
|
+
json = process_json(part, json)
|
20
|
+
rescue
|
21
|
+
raise PathError, "Expected #{json.class}\nto be an object with property #{part}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
if type == '*'
|
25
|
+
expect_all(json, &block)
|
26
|
+
elsif type == '?'
|
27
|
+
expect_one(path, json, &block)
|
28
|
+
else
|
29
|
+
yield json
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def walk_with_path(type, index, path, parts, json, &block)
|
36
|
+
last_error = nil
|
37
|
+
item_count = json.length
|
38
|
+
error_count = 0
|
39
|
+
json.each do |element|
|
40
|
+
begin
|
41
|
+
sub_path = parts[(index.next)...(parts.length)].join('.')
|
42
|
+
get_by_path(sub_path, element, &block)
|
43
|
+
rescue Exception => e
|
44
|
+
last_error = e
|
45
|
+
error_count += 1
|
46
|
+
end
|
47
|
+
ensure_match_all(last_error) if type == '*'
|
48
|
+
ensure_match_one(path, item_count, error_count) if type == '?'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_json(part, json)
|
53
|
+
if index?(part) && json.is_a?(Array)
|
54
|
+
part = part.to_i
|
55
|
+
json = json[part]
|
56
|
+
else
|
57
|
+
json = json[part.to_sym]
|
58
|
+
end
|
59
|
+
json
|
60
|
+
end
|
61
|
+
|
62
|
+
def index?(part)
|
63
|
+
part =~ /^\d+$/
|
64
|
+
end
|
65
|
+
|
66
|
+
def expect_one(path, json, &block)
|
67
|
+
item_count = json.length
|
68
|
+
error_count = 0
|
69
|
+
json.each do |part|
|
70
|
+
begin
|
71
|
+
yield part
|
72
|
+
rescue Exception
|
73
|
+
error_count += 1
|
74
|
+
ensure_match_one(path, item_count, error_count)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def expect_all(json, &block)
|
80
|
+
last_error = nil
|
81
|
+
begin
|
82
|
+
json.each { |part| yield part }
|
83
|
+
rescue Exception => e
|
84
|
+
last_error = e
|
85
|
+
end
|
86
|
+
ensure_match_all(last_error)
|
87
|
+
end
|
88
|
+
|
89
|
+
def ensure_match_one(path, item_count, error_count)
|
90
|
+
fail RSpec::Expectations::ExpectationNotMetError, "Expected one object in path #{path} to match provided JSON values" if item_count == error_count
|
91
|
+
end
|
92
|
+
|
93
|
+
def ensure_match_all(error)
|
94
|
+
fail error unless error.nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
def ensure_array(path, json)
|
98
|
+
fail RSpec::Expectations::ExpectationNotMetError, "Expected #{path} to be array got #{json.class} from JSON response" unless json.class == Array
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rack/test'
|
2
|
+
|
3
|
+
module Airborne
|
4
|
+
module RackTestRequester
|
5
|
+
def make_request(method, url, options = {})
|
6
|
+
headers = options[:headers] || {}
|
7
|
+
base_headers = Airborne.configuration.headers || {}
|
8
|
+
headers = base_headers.merge(headers)
|
9
|
+
browser = Rack::Test::Session.new(Rack::MockSession.new(Airborne.configuration.rack_app))
|
10
|
+
headers.each { |name, value| browser.header(name, value) }
|
11
|
+
browser.send(method, url, options[:body] || {}, headers)
|
12
|
+
Rack::MockResponse.class_eval do
|
13
|
+
alias_method :code, :status
|
14
|
+
end
|
15
|
+
browser.last_response
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'date'
|
3
|
+
require 'rack/utils'
|
4
|
+
|
5
|
+
module Airborne
|
6
|
+
class ExpectationError < StandardError; end
|
7
|
+
module RequestExpectations
|
8
|
+
include RSpec
|
9
|
+
include PathMatcher
|
10
|
+
|
11
|
+
def expect_json_types(*args)
|
12
|
+
call_with_path(args) do |param, body|
|
13
|
+
expect_json_types_impl(param, body)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def expect_json(*args)
|
18
|
+
call_with_path(args) do |param, body|
|
19
|
+
expect_json_impl(param, body)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def expect_json_keys(*args)
|
24
|
+
call_with_path(args) do |param, body|
|
25
|
+
expect(body.keys).to include(*param)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def expect_json_sizes(*args)
|
30
|
+
args.push(convert_expectations_for_json_sizes(args.pop))
|
31
|
+
|
32
|
+
expect_json_types(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def expect_status(code)
|
36
|
+
expect(response.code).to eq(resolve_status(code, response.code))
|
37
|
+
end
|
38
|
+
|
39
|
+
def expect_header(key, content)
|
40
|
+
expect_header_impl(key, content)
|
41
|
+
end
|
42
|
+
|
43
|
+
def expect_header_contains(key, content)
|
44
|
+
expect_header_impl(key, content, true)
|
45
|
+
end
|
46
|
+
|
47
|
+
def optional(hash)
|
48
|
+
OptionalHashTypeExpectations.new(hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
def regex(reg)
|
52
|
+
Regexp.new(reg)
|
53
|
+
end
|
54
|
+
|
55
|
+
def date
|
56
|
+
->(value) { yield DateTime.parse(value) }
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def expect_header_impl(key, content, contains = nil)
|
62
|
+
header = headers[key]
|
63
|
+
if header
|
64
|
+
if contains
|
65
|
+
expect(header.downcase).to include(content.downcase)
|
66
|
+
else
|
67
|
+
expect(header.downcase).to eq(content.downcase)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
fail RSpec::Expectations::ExpectationNotMetError, "Header #{key} not present in the HTTP response"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def expect_json_impl(expected, actual)
|
75
|
+
return if nil_optional_hash?(expected, actual)
|
76
|
+
|
77
|
+
actual = actual.to_s if expected.is_a?(Regexp)
|
78
|
+
|
79
|
+
return expect(actual).to match(expected) if property?(expected)
|
80
|
+
|
81
|
+
keys = []
|
82
|
+
|
83
|
+
keys << expected.keys if match_expected?
|
84
|
+
keys << actual.keys if match_actual?
|
85
|
+
keys = expected.keys & actual.keys if match_none?
|
86
|
+
|
87
|
+
keys.flatten.uniq.each do |prop|
|
88
|
+
expected_value = extract_expected_value(expected, prop)
|
89
|
+
actual_value = extract_actual(actual, prop)
|
90
|
+
|
91
|
+
next expect_json_impl(expected_value, actual_value) if hash?(expected_value) && hash?(actual_value)
|
92
|
+
next expected_value.call(actual_value) if expected_value.is_a?(Proc)
|
93
|
+
next expect(actual_value.to_s).to match(expected_value) if expected_value.is_a?(Regexp)
|
94
|
+
|
95
|
+
expect(actual_value).to eq(expected_value)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def expect_json_types_impl(expected, actual)
|
100
|
+
return if nil_optional_hash?(expected, actual)
|
101
|
+
|
102
|
+
@mapper ||= get_mapper
|
103
|
+
|
104
|
+
actual = convert_to_date(actual) if ((expected == :date) || (expected == :date_or_null))
|
105
|
+
|
106
|
+
return expect_type(expected, actual) if expected.is_a?(Symbol)
|
107
|
+
return expected.call(actual) if expected.is_a?(Proc)
|
108
|
+
|
109
|
+
keys = []
|
110
|
+
|
111
|
+
keys << expected.keys if match_expected?
|
112
|
+
keys << actual.keys if match_actual?
|
113
|
+
keys = expected.keys & actual.keys if match_none?
|
114
|
+
|
115
|
+
keys.flatten.uniq.each do |prop|
|
116
|
+
type = extract_expected_type(expected, prop)
|
117
|
+
value = extract_actual(actual, prop)
|
118
|
+
value = convert_to_date(value) if ((type == :date) || (type == :date_or_null))
|
119
|
+
|
120
|
+
next expect_json_types_impl(type, value) if hash?(type)
|
121
|
+
next type.call(value) if type.is_a?(Proc)
|
122
|
+
|
123
|
+
type_string = type.to_s
|
124
|
+
|
125
|
+
if type_string.include?('array_of') && !(type_string.include?('or_null') && value.nil?)
|
126
|
+
check_array_types(value, prop, type)
|
127
|
+
else
|
128
|
+
expect_type(type, value, prop)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def call_with_path(args)
|
134
|
+
if args.length == 2
|
135
|
+
get_by_path(args[0], json_body) do |json_chunk|
|
136
|
+
yield(args[1], json_chunk)
|
137
|
+
end
|
138
|
+
else
|
139
|
+
yield(args[0], json_body)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def extract_expected_value(expected, prop)
|
144
|
+
begin
|
145
|
+
raise unless expected.keys.include?(prop)
|
146
|
+
expected[prop]
|
147
|
+
rescue
|
148
|
+
raise ExpectationError, "Expectation is expected to contain property: #{prop}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def extract_expected_type(expected, prop)
|
153
|
+
begin
|
154
|
+
type = expected[prop]
|
155
|
+
type.nil? ? raise : type
|
156
|
+
rescue
|
157
|
+
raise ExpectationError, "Expectation is expected to contain property: #{prop}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def extract_actual(actual, prop)
|
162
|
+
begin
|
163
|
+
value = actual[prop]
|
164
|
+
rescue
|
165
|
+
raise ExpectationError, "Expected #{actual.class} #{actual}\nto be an object with property #{prop}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def expect_type(expected_type, value, prop_name = nil)
|
170
|
+
fail ExpectationError, "Expected type #{expected_type}\nis an invalid type" if @mapper[expected_type].nil?
|
171
|
+
|
172
|
+
insert = prop_name.nil? ? '' : "#{prop_name} to be of type"
|
173
|
+
message = "Expected #{insert} #{expected_type}\n got #{value.class} instead"
|
174
|
+
|
175
|
+
expect(@mapper[expected_type].any?{|type| value.is_a?(type)}).to eq(true), message
|
176
|
+
end
|
177
|
+
|
178
|
+
def convert_to_date(value)
|
179
|
+
begin
|
180
|
+
DateTime.parse(value)
|
181
|
+
rescue
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def check_array_types(value, prop_name, expected_type)
|
186
|
+
expect_array(value, prop_name, expected_type)
|
187
|
+
value.each do |val|
|
188
|
+
expect_type(expected_type, val, prop_name)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def nil_optional_hash?(expected, hash)
|
193
|
+
expected.is_a?(Airborne::OptionalHashTypeExpectations) && hash.nil?
|
194
|
+
end
|
195
|
+
|
196
|
+
def hash?(hash)
|
197
|
+
hash.is_a?(Hash) || hash.is_a?(Airborne::OptionalHashTypeExpectations)
|
198
|
+
end
|
199
|
+
|
200
|
+
def expect_array(value, prop_name, expected_type)
|
201
|
+
expect(value.class).to eq(Array), "Expected #{prop_name}\n to be of type #{expected_type}\n got #{value.class} instead"
|
202
|
+
end
|
203
|
+
|
204
|
+
def convert_expectations_for_json_sizes(old_expectations)
|
205
|
+
unless old_expectations.is_a?(Hash)
|
206
|
+
return convert_expectation_for_json_sizes(old_expectations)
|
207
|
+
end
|
208
|
+
|
209
|
+
old_expectations.each_with_object({}) do |(prop_name, expected_size), memo|
|
210
|
+
new_value = if expected_size.is_a?(Hash)
|
211
|
+
convert_expectations_for_json_sizes(expected_size)
|
212
|
+
else
|
213
|
+
convert_expectation_for_json_sizes(expected_size)
|
214
|
+
end
|
215
|
+
memo[prop_name] = new_value
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def convert_expectation_for_json_sizes(expected_size)
|
220
|
+
->(data) { expect(data.size).to eq(expected_size) }
|
221
|
+
end
|
222
|
+
|
223
|
+
def ensure_hash_contains_prop(prop_name, hash)
|
224
|
+
begin
|
225
|
+
yield
|
226
|
+
rescue
|
227
|
+
raise ExpectationError, "Expected #{hash.class} #{hash}\nto be an object with property #{prop_name}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def property?(expectation)
|
232
|
+
[String, Regexp, Float, Integer, TrueClass, FalseClass, NilClass, Array].any?{|type| expectation.is_a?(type)}
|
233
|
+
end
|
234
|
+
|
235
|
+
def get_mapper
|
236
|
+
base_mapper = {
|
237
|
+
integer: [Integer],
|
238
|
+
array_of_integers: [Integer],
|
239
|
+
int: [Integer],
|
240
|
+
array_of_ints: [Integer],
|
241
|
+
float: [Float, Integer],
|
242
|
+
array_of_floats: [Float, Integer],
|
243
|
+
string: [String],
|
244
|
+
array_of_strings: [String],
|
245
|
+
boolean: [TrueClass, FalseClass],
|
246
|
+
array_of_booleans: [TrueClass, FalseClass],
|
247
|
+
bool: [TrueClass, FalseClass],
|
248
|
+
array_of_bools: [TrueClass, FalseClass],
|
249
|
+
object: [Hash],
|
250
|
+
array_of_objects: [Hash],
|
251
|
+
array: [Array],
|
252
|
+
array_of_arrays: [Array],
|
253
|
+
date: [DateTime],
|
254
|
+
null: [NilClass]
|
255
|
+
}
|
256
|
+
|
257
|
+
mapper = base_mapper.clone
|
258
|
+
base_mapper.each do |key, value|
|
259
|
+
mapper[(key.to_s + '_or_null').to_sym] = value + [NilClass]
|
260
|
+
end
|
261
|
+
mapper
|
262
|
+
end
|
263
|
+
|
264
|
+
def resolve_status(candidate, authority)
|
265
|
+
candidate = Rack::Utils::SYMBOL_TO_STATUS_CODE[candidate] if candidate.is_a?(Symbol)
|
266
|
+
case authority
|
267
|
+
when String then candidate.to_s
|
268
|
+
when Integer then candidate.to_i
|
269
|
+
else candidate
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def match_none?
|
274
|
+
!match_actual? && !match_expected?
|
275
|
+
end
|
276
|
+
|
277
|
+
def match_actual?
|
278
|
+
Airborne.configuration.match_actual?
|
279
|
+
end
|
280
|
+
|
281
|
+
def match_expected?
|
282
|
+
Airborne.configuration.match_expected?
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
|
3
|
+
module Airborne
|
4
|
+
module RestClientRequester
|
5
|
+
def make_request(method, url, options = {})
|
6
|
+
headers = base_headers.merge(options[:headers] || {})
|
7
|
+
res = if method == :post || method == :patch || method == :put
|
8
|
+
begin
|
9
|
+
request_body = options[:body].nil? ? '' : options[:body]
|
10
|
+
request_body = request_body.to_json if options[:body].is_a?(Hash)
|
11
|
+
RestClient::Request.execute(:method => method, :url => get_url(url), :payload => request_body,
|
12
|
+
:headers => headers , :verify_ssl => Airborne.configuration.verify_ssl)
|
13
|
+
rescue RestClient::Exception => e
|
14
|
+
e.response
|
15
|
+
end
|
16
|
+
else
|
17
|
+
begin
|
18
|
+
RestClient::Request.execute(:method => method, :url => get_url(url), :headers => headers,
|
19
|
+
:verify_ssl => Airborne.configuration.verify_ssl)
|
20
|
+
rescue RestClient::Exception => e
|
21
|
+
e.response
|
22
|
+
end
|
23
|
+
end
|
24
|
+
res
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def base_headers
|
30
|
+
{ content_type: :json }.merge(Airborne.configuration.headers || {})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/airborne.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'airborne/optional_hash_type_expectations'
|
2
|
+
require 'airborne/path_matcher'
|
3
|
+
require 'airborne/request_expectations'
|
4
|
+
require 'airborne/rest_client_requester'
|
5
|
+
require 'airborne/rack_test_requester'
|
6
|
+
require 'airborne/base'
|
7
|
+
require 'openssl'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.add_setting :base_url
|
11
|
+
config.add_setting :verify_ssl, default: OpenSSL::SSL::VERIFY_NONE
|
12
|
+
config.add_setting :match_expected
|
13
|
+
config.add_setting :match_actual
|
14
|
+
config.add_setting :match_expected_default, default: true
|
15
|
+
config.add_setting :match_actual_default, default: false
|
16
|
+
config.add_setting :headers
|
17
|
+
config.add_setting :rack_app
|
18
|
+
config.add_setting :requester_type
|
19
|
+
config.add_setting :requester_module
|
20
|
+
config.before do |example|
|
21
|
+
config.match_expected = example.metadata[:match_expected].nil? ?
|
22
|
+
Airborne.configuration.match_expected_default? : example.metadata[:match_expected]
|
23
|
+
config.match_actual = example.metadata[:match_actual].nil? ?
|
24
|
+
Airborne.configuration.match_actual_default? : example.metadata[:match_actual]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Include last since it depends on the configuration already being added
|
28
|
+
config.include Airborne
|
29
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'base spec' do
|
4
|
+
it 'when request is made response should be set' do
|
5
|
+
mock_get('simple_get')
|
6
|
+
get '/simple_get'
|
7
|
+
expect(response).to_not be(nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'when request is made headers should be set' do
|
11
|
+
mock_get('simple_get')
|
12
|
+
get '/simple_get'
|
13
|
+
expect(headers).to_not be(nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should throw an InvalidJsonError when accessing json_body on invalid json' do
|
17
|
+
mock_get('invalid_json')
|
18
|
+
get '/invalid_json'
|
19
|
+
expect(body).to eq('invalid1234')
|
20
|
+
expect { json_body }.to raise_error(InvalidJsonError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'when request is made headers should be hash with indifferent access' do
|
24
|
+
mock_get('simple_get', 'Content-Type' => 'application/json')
|
25
|
+
get '/simple_get'
|
26
|
+
expect(headers).to be_kind_of(Hash)
|
27
|
+
expect(headers[:content_type]).to eq('application/json')
|
28
|
+
expect(headers['content_type']).to eq('application/json')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'when request is made body should be set' do
|
32
|
+
mock_get('simple_get')
|
33
|
+
get '/simple_get'
|
34
|
+
expect(body).to_not be(nil)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'when request is made json body should be symbolized hash' do
|
38
|
+
mock_get('simple_get')
|
39
|
+
get '/simple_get'
|
40
|
+
expect(json_body).to be_kind_of(Hash)
|
41
|
+
expect(json_body.first[0]).to be_kind_of(Symbol)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should handle a 500 error on get' do
|
45
|
+
mock_get('simple_get', {}, [500, 'Internal Server Error'])
|
46
|
+
get '/simple_get'
|
47
|
+
expect(json_body).to_not be(nil)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should handle a 500 error on post' do
|
51
|
+
mock_post('simple_post', {}, [500, 'Internal Server Error'])
|
52
|
+
post '/simple_post', {}
|
53
|
+
expect(json_body).to_not be(nil)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
describe 'client requester' do
|
5
|
+
before do
|
6
|
+
allow(RestClient::Request).to receive(:execute)
|
7
|
+
RSpec::Mocks.space.proxy_for(self).remove_stub_if_present(:get)
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
allow(RestClient).to receive(:send).and_call_original
|
12
|
+
Airborne.configure { |config| config.headers = {} }
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should set :content_type to :json by default' do
|
16
|
+
get '/foo'
|
17
|
+
|
18
|
+
expect(RestClient::Request).to have_received(:execute)
|
19
|
+
.with(:method => :get, :url => 'http://www.example.com/foo',
|
20
|
+
:headers => { content_type: :json }, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should override headers with option[:headers]' do
|
24
|
+
get '/foo', { content_type: 'application/x-www-form-urlencoded' }
|
25
|
+
|
26
|
+
expect(RestClient::Request).to have_received(:execute)
|
27
|
+
.with(:method => :get, :url => 'http://www.example.com/foo',
|
28
|
+
:headers => { content_type: 'application/x-www-form-urlencoded' },
|
29
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_NONE)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should override headers with airborne config headers' do
|
33
|
+
Airborne.configure { |config| config.headers = { content_type: 'text/plain' } }
|
34
|
+
|
35
|
+
get '/foo'
|
36
|
+
|
37
|
+
expect(RestClient::Request).to have_received(:execute)
|
38
|
+
.with(:method => :get, :url => 'http://www.example.com/foo',
|
39
|
+
:headers => { content_type: 'text/plain' },
|
40
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_NONE)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'expect header contains' do
|
4
|
+
it 'should ensure partial header match exists' do
|
5
|
+
mock_get('simple_get', 'Content-Type' => 'application/json')
|
6
|
+
get '/simple_get'
|
7
|
+
expect_header_contains(:content_type, 'json')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should ensure header is present' do
|
11
|
+
mock_get('simple_get', 'Content-Type' => 'application/json')
|
12
|
+
get '/simple_get'
|
13
|
+
expect { expect_header_contains(:foo, 'bar') }.to raise_error(ExpectationNotMetError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should ensure partial header is present' do
|
17
|
+
mock_get('simple_get', 'Content-Type' => 'application/json')
|
18
|
+
get '/simple_get'
|
19
|
+
expect { expect_header_contains(:content_type, 'bar') }.to raise_error(ExpectationNotMetError)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'expect header' do
|
4
|
+
it 'should find exact match for header content' do
|
5
|
+
mock_get('simple_get', 'Content-Type' => 'application/json')
|
6
|
+
get '/simple_get'
|
7
|
+
expect_header(:content_type, 'application/json')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should find exact match for header content' do
|
11
|
+
mock_get('simple_get', 'Content-Type' => 'json')
|
12
|
+
get '/simple_get'
|
13
|
+
expect { expect_header(:content_type, 'application/json') }.to raise_error(ExpectationNotMetError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should ensure correct headers are present' do
|
17
|
+
mock_get('simple_get', 'Content-Type' => 'application/json')
|
18
|
+
get '/simple_get'
|
19
|
+
expect { expect_header(:foo, 'bar') }.to raise_error(ExpectationNotMetError)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'expect_json_keys with path' do
|
4
|
+
it 'should ensure json keys with path' do
|
5
|
+
mock_get('simple_nested_path')
|
6
|
+
get '/simple_nested_path', {}
|
7
|
+
expect_json_keys('address', [:street, :city])
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should fail when keys are missing with path' do
|
11
|
+
mock_get('simple_nested_path')
|
12
|
+
get '/simple_nested_path', {}
|
13
|
+
expect { expect_json_keys('address', [:bad]) }.to raise_error(ExpectationNotMetError)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'expect_json_keys' do
|
4
|
+
it 'should fail when json keys are missing' do
|
5
|
+
mock_get('simple_json')
|
6
|
+
get '/simple_json', {}
|
7
|
+
expect { expect_json_keys([:foo, :bar, :baz, :bax]) }.to raise_error(ExpectationNotMetError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should ensure correct json keys' do
|
11
|
+
mock_get('simple_json')
|
12
|
+
get '/simple_json', {}
|
13
|
+
expect_json_keys([:foo, :bar, :baz])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should ensure correct partial json keys' do
|
17
|
+
mock_get('simple_json')
|
18
|
+
get '/simple_json', {}
|
19
|
+
expect_json_keys([:foo, :bar])
|
20
|
+
end
|
21
|
+
end
|