soaspec 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +15 -15
- data/.gitlab-ci.yml +48 -48
- data/.rspec +3 -3
- data/.rubocop.yml +2 -2
- data/CODE_OF_CONDUCT.md +74 -74
- data/ChangeLog +404 -400
- data/Gemfile +6 -6
- data/LICENSE.txt +21 -21
- data/README.md +113 -113
- data/Rakefile +24 -24
- data/Todo.md +6 -6
- data/exe/soaspec +109 -109
- data/exe/soaspec-virtual-server +156 -155
- data/exe/xml_to_yaml_file +60 -60
- data/lib/soaspec.rb +103 -103
- data/lib/soaspec/core_ext/hash.rb +83 -83
- data/lib/soaspec/exchange.rb +235 -235
- 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 +314 -314
- 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 +60 -60
- 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/id_manager.rb +31 -31
- 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/test_server/test_namespace.rb +12 -12
- data/lib/soaspec/version.rb +2 -2
- data/lib/soaspec/wsdl_generator.rb +144 -144
- data/soaspec.gemspec +46 -47
- data/test.wsdl +116 -116
- data/test.xml +10 -10
- data/test_wsdl.rb +43 -43
- metadata +6 -6
@@ -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,236 +1,236 @@
|
|
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
|
-
Soaspec.last_exchange = self
|
152
|
-
@response ||= make_request
|
153
|
-
end
|
154
|
-
|
155
|
-
alias call response
|
156
|
-
|
157
|
-
# Get status code from api class. This is http response for Web Api
|
158
|
-
# @return [Integer] Status code from api class
|
159
|
-
def status_code
|
160
|
-
exchange_handler.status_code_for(response)
|
161
|
-
end
|
162
|
-
|
163
|
-
# Dummy request used to make a request without verifying it and ignoring WSDL errors
|
164
|
-
# @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
|
165
|
-
def dummy_request
|
166
|
-
make_request
|
167
|
-
true
|
168
|
-
rescue Savon::HTTPError
|
169
|
-
puts 'Resolver error'
|
170
|
-
# This seems to occur first time IP address asks for WSDL
|
171
|
-
true
|
172
|
-
end
|
173
|
-
|
174
|
-
# @return [Boolean] Whether an element exists at the path
|
175
|
-
def element?(path)
|
176
|
-
[path]
|
177
|
-
true
|
178
|
-
rescue NoElementAtPath
|
179
|
-
false
|
180
|
-
end
|
181
|
-
|
182
|
-
# Extract value from path api class
|
183
|
-
# @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
|
184
|
-
# @return [String] Value at path
|
185
|
-
def [](path)
|
186
|
-
exchange_handler.value_from_path(response, path.to_s)
|
187
|
-
end
|
188
|
-
|
189
|
-
# Set a parameter request in the request body.
|
190
|
-
# Can be used to build a request over several steps (e.g Cucumber)
|
191
|
-
# Will be used with FactoryBot
|
192
|
-
def []=(key, value)
|
193
|
-
@override_parameters[:body] ||= {}
|
194
|
-
@override_parameters[:body][key] = value
|
195
|
-
end
|
196
|
-
|
197
|
-
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
198
|
-
# @param [Object] method_name Name of method not defined
|
199
|
-
# @param [Object] args Arguments passed to method
|
200
|
-
# @param [Object] block
|
201
|
-
def method_missing(method_name, *args, &block)
|
202
|
-
set_value = args.first
|
203
|
-
if method_name[-1] == '=' # A setter method
|
204
|
-
getter_name = method_name[0..-2]
|
205
|
-
if set_value.class < Exchange # This would be prerequisite exchange
|
206
|
-
define_singleton_method(getter_name) do
|
207
|
-
set_value
|
208
|
-
end
|
209
|
-
self[getter_name] = set_value.id if set_value.respond_to?(:id)
|
210
|
-
else
|
211
|
-
self[getter_name] = set_value
|
212
|
-
end
|
213
|
-
else
|
214
|
-
super
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
# Used for setters that are not defined
|
219
|
-
def respond_to_missing?(method_name, *args)
|
220
|
-
method_name[-1] == '=' || super
|
221
|
-
end
|
222
|
-
|
223
|
-
# Makes request, caching the response and returning self
|
224
|
-
# Used by FactoryBot
|
225
|
-
# @return [Self]
|
226
|
-
def save!
|
227
|
-
@retry_for_success = @fail_factory ? false : true
|
228
|
-
call
|
229
|
-
self
|
230
|
-
end
|
231
|
-
|
232
|
-
def to_hash
|
233
|
-
exchange_handler.to_hash(response)
|
234
|
-
end
|
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
|
+
Soaspec.last_exchange = self
|
152
|
+
@response ||= make_request
|
153
|
+
end
|
154
|
+
|
155
|
+
alias call response
|
156
|
+
|
157
|
+
# Get status code from api class. This is http response for Web Api
|
158
|
+
# @return [Integer] Status code from api class
|
159
|
+
def status_code
|
160
|
+
exchange_handler.status_code_for(response)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Dummy request used to make a request without verifying it and ignoring WSDL errors
|
164
|
+
# @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
|
165
|
+
def dummy_request
|
166
|
+
make_request
|
167
|
+
true
|
168
|
+
rescue Savon::HTTPError
|
169
|
+
puts 'Resolver error'
|
170
|
+
# This seems to occur first time IP address asks for WSDL
|
171
|
+
true
|
172
|
+
end
|
173
|
+
|
174
|
+
# @return [Boolean] Whether an element exists at the path
|
175
|
+
def element?(path)
|
176
|
+
[path]
|
177
|
+
true
|
178
|
+
rescue NoElementAtPath
|
179
|
+
false
|
180
|
+
end
|
181
|
+
|
182
|
+
# Extract value from path api class
|
183
|
+
# @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
|
184
|
+
# @return [String] Value at path
|
185
|
+
def [](path)
|
186
|
+
exchange_handler.value_from_path(response, path.to_s)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Set a parameter request in the request body.
|
190
|
+
# Can be used to build a request over several steps (e.g Cucumber)
|
191
|
+
# Will be used with FactoryBot
|
192
|
+
def []=(key, value)
|
193
|
+
@override_parameters[:body] ||= {}
|
194
|
+
@override_parameters[:body][key] = value
|
195
|
+
end
|
196
|
+
|
197
|
+
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
198
|
+
# @param [Object] method_name Name of method not defined
|
199
|
+
# @param [Object] args Arguments passed to method
|
200
|
+
# @param [Object] block
|
201
|
+
def method_missing(method_name, *args, &block)
|
202
|
+
set_value = args.first
|
203
|
+
if method_name[-1] == '=' # A setter method
|
204
|
+
getter_name = method_name[0..-2]
|
205
|
+
if set_value.class < Exchange # This would be prerequisite exchange
|
206
|
+
define_singleton_method(getter_name) do
|
207
|
+
set_value
|
208
|
+
end
|
209
|
+
self[getter_name] = set_value.id if set_value.respond_to?(:id)
|
210
|
+
else
|
211
|
+
self[getter_name] = set_value
|
212
|
+
end
|
213
|
+
else
|
214
|
+
super
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Used for setters that are not defined
|
219
|
+
def respond_to_missing?(method_name, *args)
|
220
|
+
method_name[-1] == '=' || super
|
221
|
+
end
|
222
|
+
|
223
|
+
# Makes request, caching the response and returning self
|
224
|
+
# Used by FactoryBot
|
225
|
+
# @return [Self]
|
226
|
+
def save!
|
227
|
+
@retry_for_success = @fail_factory ? false : true
|
228
|
+
call
|
229
|
+
self
|
230
|
+
end
|
231
|
+
|
232
|
+
def to_hash
|
233
|
+
exchange_handler.to_hash(response)
|
234
|
+
end
|
235
|
+
|
236
236
|
end
|