soaspec 0.1.1 → 0.1.2
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 +5 -5
- data/.gitignore +15 -15
- data/.gitlab-ci.yml +31 -31
- data/.rspec +3 -3
- data/.rubocop.yml +2 -2
- data/CODE_OF_CONDUCT.md +74 -74
- data/ChangeLog +384 -384
- data/Gemfile +6 -6
- data/LICENSE.txt +21 -21
- data/README.md +85 -85
- data/Rakefile +24 -24
- data/Todo.md +6 -6
- data/exe/soaspec +119 -119
- data/exe/soaspec-virtual-server +103 -103
- data/exe/xml_to_yaml_file +60 -60
- data/lib/soaspec.rb +91 -91
- data/lib/soaspec/core_ext/hash.rb +83 -83
- data/lib/soaspec/exchange.rb +234 -234
- data/lib/soaspec/exchange_handlers/exchange_handler.rb +103 -103
- data/lib/soaspec/exchange_handlers/handler_accessors.rb +106 -106
- data/lib/soaspec/exchange_handlers/rest_accessors.rb +92 -92
- data/lib/soaspec/exchange_handlers/rest_handler.rb +311 -311
- data/lib/soaspec/exchange_handlers/rest_methods.rb +44 -44
- data/lib/soaspec/exchange_handlers/soap_handler.rb +236 -236
- data/lib/soaspec/exe_helpers.rb +56 -56
- data/lib/soaspec/generator/.rspec.erb +5 -5
- data/lib/soaspec/generator/.travis.yml.erb +5 -5
- data/lib/soaspec/generator/Gemfile.erb +8 -8
- data/lib/soaspec/generator/README.md.erb +29 -29
- data/lib/soaspec/generator/Rakefile.erb +19 -19
- data/lib/soaspec/generator/config/data/default.yml.erb +1 -1
- data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
- data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
- data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
- data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
- data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
- data/lib/soaspec/generator/spec/spec_helper.rb.erb +20 -20
- data/lib/soaspec/generator/template/soap_template.xml +6 -6
- data/lib/soaspec/interpreter.rb +40 -40
- data/lib/soaspec/matchers.rb +65 -65
- data/lib/soaspec/not_found_errors.rb +13 -13
- data/lib/soaspec/soaspec_shared_examples.rb +24 -24
- data/lib/soaspec/spec_logger.rb +27 -27
- data/lib/soaspec/test_server/bank.wsdl +90 -90
- data/lib/soaspec/test_server/get_bank.rb +160 -160
- data/lib/soaspec/test_server/invoices.rb +27 -27
- data/lib/soaspec/test_server/namespace.xml +14 -14
- data/lib/soaspec/test_server/note.xml +5 -5
- data/lib/soaspec/test_server/puppy_service.rb +20 -20
- data/lib/soaspec/test_server/test_attribute.rb +13 -13
- data/lib/soaspec/version.rb +2 -2
- data/lib/soaspec/wsdl_generator.rb +144 -144
- data/soaspec.gemspec +46 -45
- data/test.wsdl +116 -116
- data/test.xml +10 -10
- data/test_wsdl.rb +43 -43
- metadata +17 -3
@@ -1,83 +1,83 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# Override Hash class with convience methods
|
5
|
-
class Hash
|
6
|
-
|
7
|
-
# Transform each key in Hash to a symbol. Privately used by non-self method
|
8
|
-
def self.transform_keys_to_symbols(value)
|
9
|
-
return value if not value.is_a?(Hash)
|
10
|
-
hash = value.inject({}){|memo,(k,v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
|
11
|
-
return hash
|
12
|
-
end
|
13
|
-
|
14
|
-
# Take keys of hash and transform those to a symbols
|
15
|
-
def transform_keys_to_symbols
|
16
|
-
inject({}){|memo, (k, v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
|
17
|
-
end
|
18
|
-
|
19
|
-
# Returns all keys that have a particular value within a nested Hash
|
20
|
-
def find_all_values_for(key)
|
21
|
-
result = []
|
22
|
-
result << self[key]
|
23
|
-
self.values.each do |hash_value|
|
24
|
-
# next if hash_value.is_a? Array
|
25
|
-
#
|
26
|
-
if hash_value.is_a?(Array)
|
27
|
-
hash_value.each do |array_element|
|
28
|
-
result += array_element.find_all_values_for(key) if array_element.is_a? Hash
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
values = [hash_value]
|
33
|
-
values.each do |value|
|
34
|
-
result += value.find_all_values_for(key) if value.is_a? Hash
|
35
|
-
end
|
36
|
-
end
|
37
|
-
result.compact
|
38
|
-
end
|
39
|
-
|
40
|
-
# Value present in nested Hash.
|
41
|
-
def include_value?(value)
|
42
|
-
each_value do |v|
|
43
|
-
return true if v == value
|
44
|
-
next unless v.is_a? Hash
|
45
|
-
v.each_value do |v|
|
46
|
-
return true if v == value
|
47
|
-
next unless v.is_a? Hash
|
48
|
-
v.each_value do |v|
|
49
|
-
return true if v == value
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
false
|
54
|
-
end
|
55
|
-
|
56
|
-
# # Whether key is present at least once
|
57
|
-
# def include_key?(key)
|
58
|
-
# result = find_all_values_for key
|
59
|
-
# result != []
|
60
|
-
# end
|
61
|
-
|
62
|
-
# Loop through each item within a key within a Hash if the key exists
|
63
|
-
# @param [Key] key Key within hash to iterate through
|
64
|
-
def each_if_not_null(key)
|
65
|
-
case key.class.to_s
|
66
|
-
when 'String'
|
67
|
-
if self[key]
|
68
|
-
self[key].each do |list_item|
|
69
|
-
yield(list_item)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
when 'Array', 'Hash'
|
73
|
-
if self[key[0]]
|
74
|
-
if self[key[0]][key[1]]
|
75
|
-
self[key[0]][key[1]].each do |list_item|
|
76
|
-
yield(list_item)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
# Override Hash class with convience methods
|
5
|
+
class Hash
|
6
|
+
|
7
|
+
# Transform each key in Hash to a symbol. Privately used by non-self method
|
8
|
+
def self.transform_keys_to_symbols(value)
|
9
|
+
return value if not value.is_a?(Hash)
|
10
|
+
hash = value.inject({}){|memo,(k,v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
|
11
|
+
return hash
|
12
|
+
end
|
13
|
+
|
14
|
+
# Take keys of hash and transform those to a symbols
|
15
|
+
def transform_keys_to_symbols
|
16
|
+
inject({}){|memo, (k, v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns all keys that have a particular value within a nested Hash
|
20
|
+
def find_all_values_for(key)
|
21
|
+
result = []
|
22
|
+
result << self[key]
|
23
|
+
self.values.each do |hash_value|
|
24
|
+
# next if hash_value.is_a? Array
|
25
|
+
#
|
26
|
+
if hash_value.is_a?(Array)
|
27
|
+
hash_value.each do |array_element|
|
28
|
+
result += array_element.find_all_values_for(key) if array_element.is_a? Hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
values = [hash_value]
|
33
|
+
values.each do |value|
|
34
|
+
result += value.find_all_values_for(key) if value.is_a? Hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
result.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
# Value present in nested Hash.
|
41
|
+
def include_value?(value)
|
42
|
+
each_value do |v|
|
43
|
+
return true if v == value
|
44
|
+
next unless v.is_a? Hash
|
45
|
+
v.each_value do |v|
|
46
|
+
return true if v == value
|
47
|
+
next unless v.is_a? Hash
|
48
|
+
v.each_value do |v|
|
49
|
+
return true if v == value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
# # Whether key is present at least once
|
57
|
+
# def include_key?(key)
|
58
|
+
# result = find_all_values_for key
|
59
|
+
# result != []
|
60
|
+
# end
|
61
|
+
|
62
|
+
# Loop through each item within a key within a Hash if the key exists
|
63
|
+
# @param [Key] key Key within hash to iterate through
|
64
|
+
def each_if_not_null(key)
|
65
|
+
case key.class.to_s
|
66
|
+
when 'String'
|
67
|
+
if self[key]
|
68
|
+
self[key].each do |list_item|
|
69
|
+
yield(list_item)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
when 'Array', 'Hash'
|
73
|
+
if self[key[0]]
|
74
|
+
if self[key[0]][key[1]]
|
75
|
+
self[key[0]][key[1]].each do |list_item|
|
76
|
+
yield(list_item)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/soaspec/exchange.rb
CHANGED
@@ -1,235 +1,235 @@
|
|
1
|
-
require_relative '../soaspec'
|
2
|
-
|
3
|
-
# Convenience methods to set Exchange specific properties
|
4
|
-
module ExchangeAccessors
|
5
|
-
|
6
|
-
# Set default exchange handler for this exchange
|
7
|
-
# This is helpful for when you need a new exchange handler created for each exchange
|
8
|
-
def default_handler(handler_class, name = handler_class.to_s, params = '')
|
9
|
-
define_method('default_handler_used') do
|
10
|
-
params_used = Hash[params.map do |k, param|
|
11
|
-
[k, param.is_a?(String) ? ERB.new(param).result(binding) : param]
|
12
|
-
end]
|
13
|
-
handler_class.new name, params_used
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# Set retry_for_success to true, retrying response until a successful status code is returned
|
18
|
-
def expect_positive_status(retry_count: 3)
|
19
|
-
define_method('retry_count') do
|
20
|
-
retry_count
|
21
|
-
end
|
22
|
-
define_method('retry_for_success?') do
|
23
|
-
true
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
# This represents a request / response pair
|
30
|
-
# Essentially, params in the exchange that are set are related to the request
|
31
|
-
# What is returned is related to the response
|
32
|
-
class Exchange
|
33
|
-
extend ExchangeAccessors
|
34
|
-
|
35
|
-
# Instance of ExchangeHandler for which this exchange is made
|
36
|
-
attr_accessor :exchange_handler
|
37
|
-
# How many times to retry for a success
|
38
|
-
attr_accessor :retry_count
|
39
|
-
# Name used for displaying class
|
40
|
-
attr_accessor :test_name
|
41
|
-
# Expect Factory to fail upon trying to create
|
42
|
-
attr_writer :fail_factory
|
43
|
-
|
44
|
-
|
45
|
-
def values_from_path(path, attribute: nil)
|
46
|
-
exchange_handler.values_from_path(response, path, attribute: attribute)
|
47
|
-
end
|
48
|
-
|
49
|
-
# Set retry for success variable to true so that request will be retried
|
50
|
-
# for retry_count until it's true
|
51
|
-
def retry_for_success
|
52
|
-
@retry_for_success = true
|
53
|
-
self
|
54
|
-
end
|
55
|
-
|
56
|
-
# @return [Bool] Whether to keep making request until success code reached
|
57
|
-
def retry_for_success?
|
58
|
-
@retry_for_success
|
59
|
-
end
|
60
|
-
|
61
|
-
# @return [Boolean] Soaspec::ExchangeHandler used by this exchange
|
62
|
-
def default_handler_used
|
63
|
-
nil
|
64
|
-
end
|
65
|
-
|
66
|
-
# @param [String] element Element to define methods for
|
67
|
-
def methods_for_element(element)
|
68
|
-
element_name = element.to_s.split('__custom_path_').last
|
69
|
-
define_singleton_method(element_name) do
|
70
|
-
exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
|
71
|
-
end
|
72
|
-
define_singleton_method("#{element_name}?") do
|
73
|
-
begin
|
74
|
-
__send__ element_name
|
75
|
-
true
|
76
|
-
rescue NoElementAtPath
|
77
|
-
false
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# @param [Symbol, String] name Name shown in RSpec run
|
83
|
-
# @param [Hash] override_parameters Parameters to override for default params
|
84
|
-
def initialize(name = self.class.to_s, override_parameters = {})
|
85
|
-
self.test_name ||= name.to_s
|
86
|
-
# As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
|
87
|
-
@exchange_handler ||= default_handler_used || Soaspec.api_handler
|
88
|
-
raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
|
89
|
-
@fail_factory = nil
|
90
|
-
@override_parameters = override_parameters
|
91
|
-
@retry_for_success = false
|
92
|
-
self.retry_count = 3
|
93
|
-
@exchange_handler.elements.each { |element| methods_for_element(element) }
|
94
|
-
end
|
95
|
-
|
96
|
-
# Specify a url to add onto the base_url of the ExchangeHandler used
|
97
|
-
# @param [String] url Url to add onto the base_url of the ExchangeHandler used
|
98
|
-
def suburl=(url)
|
99
|
-
@override_parameters[:suburl] = url
|
100
|
-
end
|
101
|
-
|
102
|
-
# Specify HTTP method to use. Default is :post
|
103
|
-
# @param [Symbol] method HTTP method. E.g, :get, :patch
|
104
|
-
def method=(method)
|
105
|
-
@override_parameters[:method] = method
|
106
|
-
end
|
107
|
-
|
108
|
-
# Make request to handler with parameters defined
|
109
|
-
# Will retry until success code reached if retry_for_success? is set
|
110
|
-
# @return [Response] Response from Api handler
|
111
|
-
def make_request
|
112
|
-
Soaspec::SpecLogger.info 'Example ' + test_name
|
113
|
-
request_params = @override_parameters
|
114
|
-
(1..retry_count).each do |count|
|
115
|
-
response = exchange_handler.make_request(request_params)
|
116
|
-
return response unless retry_for_success?
|
117
|
-
return response if (200..299).cover? @exchange_handler.status_code_for(response)
|
118
|
-
sleep 0.5
|
119
|
-
break response if count == retry_count
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# Stores a value in the api handler that can be accessed by the provided name
|
124
|
-
# @param [Symbol] name Name of method to use to access this value within handler
|
125
|
-
# @param [String] value Path to value to store
|
126
|
-
def store(name, value)
|
127
|
-
exchange_handler.store(name, self[value])
|
128
|
-
end
|
129
|
-
|
130
|
-
# Retrieve the stored value from the Api Handler
|
131
|
-
# @param [String, Symbol] name Name of value to retrieve
|
132
|
-
# @return [Object] value from the Api Handler stored previously
|
133
|
-
def retrieve(name)
|
134
|
-
method = '__stored_val__' + name.to_s
|
135
|
-
raise ArgumentError('Value not stored at ') unless exchange_handler.respond_to? method
|
136
|
-
exchange_handler.send(method)
|
137
|
-
end
|
138
|
-
|
139
|
-
# Name describing this class when used with `RSpec.describe`
|
140
|
-
# This will make the request and store the response
|
141
|
-
# @return [String] Name given when initializing
|
142
|
-
def to_s
|
143
|
-
test_name
|
144
|
-
end
|
145
|
-
|
146
|
-
# Returns response object from Api. Will make the request if not made and then cache it for later on
|
147
|
-
# For example for SOAP it will be a Savon response
|
148
|
-
# response.body (body of response as Hash)
|
149
|
-
# response.header (head of response as Hash)
|
150
|
-
def response
|
151
|
-
@response ||= make_request
|
152
|
-
end
|
153
|
-
|
154
|
-
alias call response
|
155
|
-
|
156
|
-
# Get status code from api class. This is http response for Web Api
|
157
|
-
# @return [Integer] Status code from api class
|
158
|
-
def status_code
|
159
|
-
exchange_handler.status_code_for(response)
|
160
|
-
end
|
161
|
-
|
162
|
-
# Dummy request used to make a request without verifying it and ignoring WSDL errors
|
163
|
-
# @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
|
164
|
-
def dummy_request
|
165
|
-
make_request
|
166
|
-
true
|
167
|
-
rescue Savon::HTTPError
|
168
|
-
puts 'Resolver error'
|
169
|
-
# This seems to occur first time IP address asks for WSDL
|
170
|
-
true
|
171
|
-
end
|
172
|
-
|
173
|
-
# @return [Boolean] Whether an element exists at the path
|
174
|
-
def element?(path)
|
175
|
-
[path]
|
176
|
-
true
|
177
|
-
rescue NoElementAtPath
|
178
|
-
false
|
179
|
-
end
|
180
|
-
|
181
|
-
# Extract value from path api class
|
182
|
-
# @param [Object] path Path to return element for api class E.g - for SOAP this is XPath string. For JSON, this is Hash dig Array
|
183
|
-
# @return [String] Value at path
|
184
|
-
def [](path)
|
185
|
-
exchange_handler.value_from_path(response, path.to_s)
|
186
|
-
end
|
187
|
-
|
188
|
-
# Set a parameter request in the request body.
|
189
|
-
# Can be used to build a request over several steps (e.g Cucumber)
|
190
|
-
# Will be used with FactoryBot
|
191
|
-
def []=(key, value)
|
192
|
-
@override_parameters[:body] ||= {}
|
193
|
-
@override_parameters[:body][key] = value
|
194
|
-
end
|
195
|
-
|
196
|
-
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
197
|
-
# @param [Object] method_name Name of method not defined
|
198
|
-
# @param [Object] args Arguments passed to method
|
199
|
-
# @param [Object] block
|
200
|
-
def method_missing(method_name, *args, &block)
|
201
|
-
set_value = args.first
|
202
|
-
if method_name[-1] == '=' # A setter method
|
203
|
-
getter_name = method_name[0..-2]
|
204
|
-
if set_value.class < Exchange # This would be prerequisite exchange
|
205
|
-
define_singleton_method(getter_name) do
|
206
|
-
set_value
|
207
|
-
end
|
208
|
-
self[getter_name] = set_value.id if set_value.respond_to?(:id)
|
209
|
-
else
|
210
|
-
self[getter_name] = set_value
|
211
|
-
end
|
212
|
-
else
|
213
|
-
super
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
# Used for setters that are not defined
|
218
|
-
def respond_to_missing?(method_name, *args)
|
219
|
-
method_name[-1] == '=' || super
|
220
|
-
end
|
221
|
-
|
222
|
-
# Makes request, caching the response and returning self
|
223
|
-
# Used by FactoryBot
|
224
|
-
# @return [Self]
|
225
|
-
def save!
|
226
|
-
@retry_for_success = @fail_factory ? false : true
|
227
|
-
call
|
228
|
-
self
|
229
|
-
end
|
230
|
-
|
231
|
-
def to_hash
|
232
|
-
exchange_handler.to_hash(response)
|
233
|
-
end
|
234
|
-
|
1
|
+
require_relative '../soaspec'
|
2
|
+
|
3
|
+
# Convenience methods to set Exchange specific properties
|
4
|
+
module ExchangeAccessors
|
5
|
+
|
6
|
+
# Set default exchange handler for this exchange
|
7
|
+
# This is helpful for when you need a new exchange handler created for each exchange
|
8
|
+
def default_handler(handler_class, name = handler_class.to_s, params = '')
|
9
|
+
define_method('default_handler_used') do
|
10
|
+
params_used = Hash[params.map do |k, param|
|
11
|
+
[k, param.is_a?(String) ? ERB.new(param).result(binding) : param]
|
12
|
+
end]
|
13
|
+
handler_class.new name, params_used
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set retry_for_success to true, retrying response until a successful status code is returned
|
18
|
+
def expect_positive_status(retry_count: 3)
|
19
|
+
define_method('retry_count') do
|
20
|
+
retry_count
|
21
|
+
end
|
22
|
+
define_method('retry_for_success?') do
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# This represents a request / response pair
|
30
|
+
# Essentially, params in the exchange that are set are related to the request
|
31
|
+
# What is returned is related to the response
|
32
|
+
class Exchange
|
33
|
+
extend ExchangeAccessors
|
34
|
+
|
35
|
+
# Instance of ExchangeHandler for which this exchange is made
|
36
|
+
attr_accessor :exchange_handler
|
37
|
+
# How many times to retry for a success
|
38
|
+
attr_accessor :retry_count
|
39
|
+
# Name used for displaying class
|
40
|
+
attr_accessor :test_name
|
41
|
+
# Expect Factory to fail upon trying to create
|
42
|
+
attr_writer :fail_factory
|
43
|
+
|
44
|
+
|
45
|
+
def values_from_path(path, attribute: nil)
|
46
|
+
exchange_handler.values_from_path(response, path, attribute: attribute)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Set retry for success variable to true so that request will be retried
|
50
|
+
# for retry_count until it's true
|
51
|
+
def retry_for_success
|
52
|
+
@retry_for_success = true
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [Bool] Whether to keep making request until success code reached
|
57
|
+
def retry_for_success?
|
58
|
+
@retry_for_success
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Boolean] Soaspec::ExchangeHandler used by this exchange
|
62
|
+
def default_handler_used
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [String] element Element to define methods for
|
67
|
+
def methods_for_element(element)
|
68
|
+
element_name = element.to_s.split('__custom_path_').last
|
69
|
+
define_singleton_method(element_name) do
|
70
|
+
exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
|
71
|
+
end
|
72
|
+
define_singleton_method("#{element_name}?") do
|
73
|
+
begin
|
74
|
+
__send__ element_name
|
75
|
+
true
|
76
|
+
rescue NoElementAtPath
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param [Symbol, String] name Name shown in RSpec run
|
83
|
+
# @param [Hash] override_parameters Parameters to override for default params
|
84
|
+
def initialize(name = self.class.to_s, override_parameters = {})
|
85
|
+
self.test_name ||= name.to_s
|
86
|
+
# As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
|
87
|
+
@exchange_handler ||= default_handler_used || Soaspec.api_handler
|
88
|
+
raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
|
89
|
+
@fail_factory = nil
|
90
|
+
@override_parameters = override_parameters
|
91
|
+
@retry_for_success = false
|
92
|
+
self.retry_count = 3
|
93
|
+
@exchange_handler.elements.each { |element| methods_for_element(element) }
|
94
|
+
end
|
95
|
+
|
96
|
+
# Specify a url to add onto the base_url of the ExchangeHandler used
|
97
|
+
# @param [String] url Url to add onto the base_url of the ExchangeHandler used
|
98
|
+
def suburl=(url)
|
99
|
+
@override_parameters[:suburl] = url
|
100
|
+
end
|
101
|
+
|
102
|
+
# Specify HTTP method to use. Default is :post
|
103
|
+
# @param [Symbol] method HTTP method. E.g, :get, :patch
|
104
|
+
def method=(method)
|
105
|
+
@override_parameters[:method] = method
|
106
|
+
end
|
107
|
+
|
108
|
+
# Make request to handler with parameters defined
|
109
|
+
# Will retry until success code reached if retry_for_success? is set
|
110
|
+
# @return [Response] Response from Api handler
|
111
|
+
def make_request
|
112
|
+
Soaspec::SpecLogger.info 'Example ' + test_name
|
113
|
+
request_params = @override_parameters
|
114
|
+
(1..retry_count).each do |count|
|
115
|
+
response = exchange_handler.make_request(request_params)
|
116
|
+
return response unless retry_for_success?
|
117
|
+
return response if (200..299).cover? @exchange_handler.status_code_for(response)
|
118
|
+
sleep 0.5
|
119
|
+
break response if count == retry_count
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Stores a value in the api handler that can be accessed by the provided name
|
124
|
+
# @param [Symbol] name Name of method to use to access this value within handler
|
125
|
+
# @param [String] value Path to value to store
|
126
|
+
def store(name, value)
|
127
|
+
exchange_handler.store(name, self[value])
|
128
|
+
end
|
129
|
+
|
130
|
+
# Retrieve the stored value from the Api Handler
|
131
|
+
# @param [String, Symbol] name Name of value to retrieve
|
132
|
+
# @return [Object] value from the Api Handler stored previously
|
133
|
+
def retrieve(name)
|
134
|
+
method = '__stored_val__' + name.to_s
|
135
|
+
raise ArgumentError('Value not stored at ') unless exchange_handler.respond_to? method
|
136
|
+
exchange_handler.send(method)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Name describing this class when used with `RSpec.describe`
|
140
|
+
# This will make the request and store the response
|
141
|
+
# @return [String] Name given when initializing
|
142
|
+
def to_s
|
143
|
+
test_name
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns response object from Api. Will make the request if not made and then cache it for later on
|
147
|
+
# For example for SOAP it will be a Savon response
|
148
|
+
# response.body (body of response as Hash)
|
149
|
+
# response.header (head of response as Hash)
|
150
|
+
def response
|
151
|
+
@response ||= make_request
|
152
|
+
end
|
153
|
+
|
154
|
+
alias call response
|
155
|
+
|
156
|
+
# Get status code from api class. This is http response for Web Api
|
157
|
+
# @return [Integer] Status code from api class
|
158
|
+
def status_code
|
159
|
+
exchange_handler.status_code_for(response)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Dummy request used to make a request without verifying it and ignoring WSDL errors
|
163
|
+
# @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
|
164
|
+
def dummy_request
|
165
|
+
make_request
|
166
|
+
true
|
167
|
+
rescue Savon::HTTPError
|
168
|
+
puts 'Resolver error'
|
169
|
+
# This seems to occur first time IP address asks for WSDL
|
170
|
+
true
|
171
|
+
end
|
172
|
+
|
173
|
+
# @return [Boolean] Whether an element exists at the path
|
174
|
+
def element?(path)
|
175
|
+
[path]
|
176
|
+
true
|
177
|
+
rescue NoElementAtPath
|
178
|
+
false
|
179
|
+
end
|
180
|
+
|
181
|
+
# Extract value from path api class
|
182
|
+
# @param [Object] path Path to return element for api class E.g - for SOAP this is XPath string. For JSON, this is Hash dig Array
|
183
|
+
# @return [String] Value at path
|
184
|
+
def [](path)
|
185
|
+
exchange_handler.value_from_path(response, path.to_s)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Set a parameter request in the request body.
|
189
|
+
# Can be used to build a request over several steps (e.g Cucumber)
|
190
|
+
# Will be used with FactoryBot
|
191
|
+
def []=(key, value)
|
192
|
+
@override_parameters[:body] ||= {}
|
193
|
+
@override_parameters[:body][key] = value
|
194
|
+
end
|
195
|
+
|
196
|
+
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
197
|
+
# @param [Object] method_name Name of method not defined
|
198
|
+
# @param [Object] args Arguments passed to method
|
199
|
+
# @param [Object] block
|
200
|
+
def method_missing(method_name, *args, &block)
|
201
|
+
set_value = args.first
|
202
|
+
if method_name[-1] == '=' # A setter method
|
203
|
+
getter_name = method_name[0..-2]
|
204
|
+
if set_value.class < Exchange # This would be prerequisite exchange
|
205
|
+
define_singleton_method(getter_name) do
|
206
|
+
set_value
|
207
|
+
end
|
208
|
+
self[getter_name] = set_value.id if set_value.respond_to?(:id)
|
209
|
+
else
|
210
|
+
self[getter_name] = set_value
|
211
|
+
end
|
212
|
+
else
|
213
|
+
super
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Used for setters that are not defined
|
218
|
+
def respond_to_missing?(method_name, *args)
|
219
|
+
method_name[-1] == '=' || super
|
220
|
+
end
|
221
|
+
|
222
|
+
# Makes request, caching the response and returning self
|
223
|
+
# Used by FactoryBot
|
224
|
+
# @return [Self]
|
225
|
+
def save!
|
226
|
+
@retry_for_success = @fail_factory ? false : true
|
227
|
+
call
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
def to_hash
|
232
|
+
exchange_handler.to_hash(response)
|
233
|
+
end
|
234
|
+
|
235
235
|
end
|