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,45 +1,45 @@
|
|
1
|
-
|
2
|
-
module Soaspec
|
3
|
-
# Contains commonly used REST methods
|
4
|
-
module RestMethods
|
5
|
-
# Make REST Post Exchange
|
6
|
-
# @param [String] name Name of test displayed
|
7
|
-
# @param [Hash] params Exchange parameters
|
8
|
-
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
9
|
-
def post(name, params = {})
|
10
|
-
Exchange.new(name, method: :post, **params)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Make REST Patch Exchange
|
14
|
-
# @param [String] name Name of test displayed
|
15
|
-
# @param [Hash] params Exchange parameters
|
16
|
-
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
17
|
-
def patch(name, params = {})
|
18
|
-
Exchange.new(name, method: :patch, **params)
|
19
|
-
end
|
20
|
-
|
21
|
-
# Make REST Put Exchange
|
22
|
-
# @param [String] name Name of test displayed
|
23
|
-
# @param [Hash] params Exchange parameters
|
24
|
-
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
25
|
-
def put(name, params = {})
|
26
|
-
Exchange.new(name, method: :put, **params)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Make REST Get Exchange
|
30
|
-
# @param [String] name Name of test displayed
|
31
|
-
# @param [Hash] params Exchange parameters
|
32
|
-
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
33
|
-
def get(name, params = {})
|
34
|
-
Exchange.new(name, method: :get, **params)
|
35
|
-
end
|
36
|
-
|
37
|
-
# Make REST Delete Exchange
|
38
|
-
# @param [String] name Name of test displayed
|
39
|
-
# @param [Hash] params Exchange parameters
|
40
|
-
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
41
|
-
def delete(name, params = {})
|
42
|
-
Exchange.new(name, method: :delete, **params)
|
43
|
-
end
|
44
|
-
end
|
1
|
+
|
2
|
+
module Soaspec
|
3
|
+
# Contains commonly used REST methods
|
4
|
+
module RestMethods
|
5
|
+
# Make REST Post Exchange
|
6
|
+
# @param [String] name Name of test displayed
|
7
|
+
# @param [Hash] params Exchange parameters
|
8
|
+
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
9
|
+
def post(name, params = {})
|
10
|
+
Exchange.new(name, method: :post, **params)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Make REST Patch Exchange
|
14
|
+
# @param [String] name Name of test displayed
|
15
|
+
# @param [Hash] params Exchange parameters
|
16
|
+
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
17
|
+
def patch(name, params = {})
|
18
|
+
Exchange.new(name, method: :patch, **params)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Make REST Put Exchange
|
22
|
+
# @param [String] name Name of test displayed
|
23
|
+
# @param [Hash] params Exchange parameters
|
24
|
+
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
25
|
+
def put(name, params = {})
|
26
|
+
Exchange.new(name, method: :put, **params)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Make REST Get Exchange
|
30
|
+
# @param [String] name Name of test displayed
|
31
|
+
# @param [Hash] params Exchange parameters
|
32
|
+
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
33
|
+
def get(name, params = {})
|
34
|
+
Exchange.new(name, method: :get, **params)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Make REST Delete Exchange
|
38
|
+
# @param [String] name Name of test displayed
|
39
|
+
# @param [Hash] params Exchange parameters
|
40
|
+
# @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
|
41
|
+
def delete(name, params = {})
|
42
|
+
Exchange.new(name, method: :delete, **params)
|
43
|
+
end
|
44
|
+
end
|
45
45
|
end
|
@@ -1,237 +1,237 @@
|
|
1
|
-
|
2
|
-
require_relative 'exchange_handler'
|
3
|
-
require_relative '../core_ext/hash'
|
4
|
-
require_relative '../not_found_errors'
|
5
|
-
require_relative 'handler_accessors'
|
6
|
-
require_relative '../interpreter'
|
7
|
-
require 'forwardable'
|
8
|
-
|
9
|
-
module Soaspec
|
10
|
-
|
11
|
-
# Accessors specific to SOAP handler
|
12
|
-
module SoapAccessors
|
13
|
-
# Define attributes set on root SOAP element
|
14
|
-
def root_attributes(attributes)
|
15
|
-
define_method('request_root_attributes') do
|
16
|
-
attributes
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Wraps around Savon client defining default values dependent on the soap request
|
22
|
-
class SoapHandler < ExchangeHandler
|
23
|
-
extend Soaspec::SoapAccessors
|
24
|
-
extend Forwardable
|
25
|
-
|
26
|
-
delegate [:operations] => :client
|
27
|
-
|
28
|
-
# Savon client used to make SOAP calls
|
29
|
-
attr_accessor :client
|
30
|
-
# SOAP Operation to use by default
|
31
|
-
attr_accessor :operation
|
32
|
-
|
33
|
-
# Attributes set at the root XML element of SOAP request
|
34
|
-
def request_root_attributes
|
35
|
-
nil
|
36
|
-
end
|
37
|
-
|
38
|
-
# Options to log xml request and response
|
39
|
-
def logging_options
|
40
|
-
{
|
41
|
-
log: true, # See request and response. (Put this in traffic file)
|
42
|
-
log_level: :debug,
|
43
|
-
logger: Soaspec::SpecLogger.create,
|
44
|
-
pretty_print_xml: true # Prints XML pretty
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
# Default Savon options. See http://savonrb.com/version2/globals.html for details
|
49
|
-
# @return [Hash] Default Savon options for all BasicSoapHandler
|
50
|
-
def default_options
|
51
|
-
{
|
52
|
-
ssl_verify_mode: :none, # Easier for testing. Not so secure
|
53
|
-
follow_redirects: true, # Necessary for many API calls
|
54
|
-
soap_version: 2, # use SOAP 1.2. You will get 415 error if this is incorrect
|
55
|
-
raise_errors: false # HTTP errors not cause failure as often negative test scenarios expect not 200 response
|
56
|
-
# Things could go wrong if not set properly
|
57
|
-
# env_namespace: :soap, # Change environment namespace
|
58
|
-
# namespace_identifier: :tst, # Change namespace element
|
59
|
-
# element_form_default: :qualified # Populate each element with namespace
|
60
|
-
# namespace: 'http://Extended_namespace.xsd' change root namespace
|
61
|
-
# basic_auth: 'user', 'password'
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
# Add values to here when extending this class to have default Savon options.
|
66
|
-
# See http://savonrb.com/version2/globals.html for details
|
67
|
-
# @return [Hash] Savon options adding to & overriding defaults
|
68
|
-
def savon_options
|
69
|
-
{
|
70
|
-
}
|
71
|
-
end
|
72
|
-
|
73
|
-
# Setup object to handle communicating with a particular SOAP WSDL
|
74
|
-
# @param [Hash] options Options defining SOAP request. WSDL, authentication, see http://savonrb.com/version2/globals.html for list of options
|
75
|
-
def initialize(name = self.class.to_s, options = {})
|
76
|
-
@default_hash = {}
|
77
|
-
@request_option = :hash
|
78
|
-
if name.is_a?(Hash) && options == {} # If name is not set
|
79
|
-
options = name
|
80
|
-
name = self.class.to_s
|
81
|
-
end
|
82
|
-
super
|
83
|
-
set_remove_key(options, :operation)
|
84
|
-
set_remove_key(options, :default_hash)
|
85
|
-
set_remove_key(options, :template_name)
|
86
|
-
merged_options = Soaspec.log_api_traffic? ? default_options.merge(logging_options) : default_options
|
87
|
-
merged_options.merge! savon_options
|
88
|
-
merged_options.merge!(options)
|
89
|
-
self.client = Savon.client(merged_options)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Used in making request via hash or in template via Erb
|
93
|
-
def request_body_params(request_parameters)
|
94
|
-
test_values = request_parameters[:body] || request_parameters
|
95
|
-
test_values.transform_keys_to_symbols if Soaspec.always_use_keys?
|
96
|
-
end
|
97
|
-
|
98
|
-
# Used in together with Exchange request that passes such override parameters
|
99
|
-
# @param [Hash] request_parameters Parameters used to overwrite defaults in request
|
100
|
-
def make_request(request_parameters)
|
101
|
-
test_values = request_body_params request_parameters
|
102
|
-
begin
|
103
|
-
if @request_option == :template
|
104
|
-
request_body = File.read('template/' + template_name)
|
105
|
-
render_body = ERB.new(request_body).result(binding)
|
106
|
-
client.call(operation, xml: render_body) # Call the SOAP operation with the request XML provided
|
107
|
-
elsif @request_option == :hash
|
108
|
-
client.call(operation, message: @default_hash.merge(test_values), attributes: request_root_attributes)
|
109
|
-
end
|
110
|
-
rescue Savon::HTTPError => e
|
111
|
-
e
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# @param [Hash] format Format of expected result
|
116
|
-
# @return [Object] Generic body to be displayed in error messages
|
117
|
-
def response_body(response, format: :hash)
|
118
|
-
case format
|
119
|
-
when :hash
|
120
|
-
response.body
|
121
|
-
when :raw
|
122
|
-
response.xml
|
123
|
-
else
|
124
|
-
response.body
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
# @return [Boolean] Whether the request found the desired value or not
|
129
|
-
def found?(response)
|
130
|
-
status_code_for(response) != 404
|
131
|
-
end
|
132
|
-
|
133
|
-
# Response status code for response. '200' indicates a success
|
134
|
-
# @param [Savon::Response] response
|
135
|
-
# @return [Integer] Status code
|
136
|
-
def status_code_for(response)
|
137
|
-
response.http.code
|
138
|
-
end
|
139
|
-
|
140
|
-
# @return [Boolean] Whether response includes provided string within it
|
141
|
-
def include_in_body?(response, expected)
|
142
|
-
response.to_xml.to_s.include? expected
|
143
|
-
end
|
144
|
-
|
145
|
-
# @param [Symbol] expected
|
146
|
-
# @return [Boolean] Whether response body contains expected key
|
147
|
-
def include_key?(response, expected)
|
148
|
-
body = response.body
|
149
|
-
body.extend Hashie::Extensions::DeepFind
|
150
|
-
!body.deep_find_all(expected).empty?
|
151
|
-
end
|
152
|
-
|
153
|
-
# Convert all XML nodes to lowercase
|
154
|
-
# @param [Nokogiri::XML::Document]
|
155
|
-
def convert_to_lower_case(xml_doc)
|
156
|
-
xml_doc.traverse do |node|
|
157
|
-
node.name = node.name.downcase if node.kind_of?(Nokogiri::XML::Element)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
# Returns the value at the provided xpath
|
162
|
-
# @param [Savon::Response] response
|
163
|
-
# @param [String] xpath
|
164
|
-
# @return [Enumerable] Elements found through Xpath
|
165
|
-
def xpath_elements_for(response: nil, xpath: nil, attribute: nil)
|
166
|
-
raise ArgumentError('response and xpath must be passed to method') unless response && xpath
|
167
|
-
xpath = "//*[@#{attribute}]" unless attribute.nil?
|
168
|
-
xpath = '//' + xpath if xpath[0] != '/'
|
169
|
-
temp_doc = response.doc.dup
|
170
|
-
convert_to_lower_case(temp_doc) if convert_to_lower?
|
171
|
-
if strip_namespaces? && !xpath.include?(':')
|
172
|
-
temp_doc.remove_namespaces!
|
173
|
-
temp_doc.xpath(xpath)
|
174
|
-
else
|
175
|
-
temp_doc.xpath(xpath, temp_doc.collect_namespaces)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
# Based on a exchange, return the value at the provided xpath
|
180
|
-
# If the path does not begin with a '/', a '//' is added to it
|
181
|
-
# @param [Savon::Response] response
|
182
|
-
# @param [String] path Xpath
|
183
|
-
# @param [String] attribute Generic attribute to find. Will override path
|
184
|
-
# @return [String] Value at Xpath
|
185
|
-
def value_from_path(response, path, attribute: nil)
|
186
|
-
results = xpath_elements_for(response: response, xpath: path, attribute: attribute)
|
187
|
-
raise NoElementAtPath, "No value at Xpath '#{path}' in XML #{response.doc}" if results.empty?
|
188
|
-
return results.first.inner_text if attribute.nil?
|
189
|
-
results.first.attributes[attribute].inner_text
|
190
|
-
end
|
191
|
-
|
192
|
-
# @return [Enumerable] List of values returned from path
|
193
|
-
def values_from_path(response, path, attribute: nil)
|
194
|
-
xpath_elements_for(response: response, xpath: path, attribute: attribute).map(&:inner_text)
|
195
|
-
end
|
196
|
-
|
197
|
-
# alias elements xpath_elements_for
|
198
|
-
|
199
|
-
# @return [Boolean] Whether any of the keys of the Body Hash include value
|
200
|
-
def include_value?(response, expected_value)
|
201
|
-
response.body.include_value?(expected_value)
|
202
|
-
end
|
203
|
-
|
204
|
-
# Hash of response body
|
205
|
-
def to_hash(response)
|
206
|
-
response.body
|
207
|
-
end
|
208
|
-
|
209
|
-
# Convenience methods for once off usage of a SOAP request
|
210
|
-
class << self
|
211
|
-
|
212
|
-
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
213
|
-
# @param [Object] method_name Name of method not defined
|
214
|
-
# @param [Object] args Arguments passed to method
|
215
|
-
# @param [Object] block
|
216
|
-
def method_missing(method_name, *args, &block)
|
217
|
-
tmp_class = new(method_name)
|
218
|
-
operations = tmp_class.operations
|
219
|
-
if operations.include? method_name
|
220
|
-
tmp_class.operation = method_name
|
221
|
-
exchange = Exchange.new(method_name, *args)
|
222
|
-
exchange.exchange_handler = tmp_class
|
223
|
-
exchange
|
224
|
-
else
|
225
|
-
super
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def respond_to_missing?(method_name, *args)
|
230
|
-
tmp_class = new(args)
|
231
|
-
operations = tmp_class.operations
|
232
|
-
operations.include?(method_name) || super
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
end
|
1
|
+
|
2
|
+
require_relative 'exchange_handler'
|
3
|
+
require_relative '../core_ext/hash'
|
4
|
+
require_relative '../not_found_errors'
|
5
|
+
require_relative 'handler_accessors'
|
6
|
+
require_relative '../interpreter'
|
7
|
+
require 'forwardable'
|
8
|
+
|
9
|
+
module Soaspec
|
10
|
+
|
11
|
+
# Accessors specific to SOAP handler
|
12
|
+
module SoapAccessors
|
13
|
+
# Define attributes set on root SOAP element
|
14
|
+
def root_attributes(attributes)
|
15
|
+
define_method('request_root_attributes') do
|
16
|
+
attributes
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Wraps around Savon client defining default values dependent on the soap request
|
22
|
+
class SoapHandler < ExchangeHandler
|
23
|
+
extend Soaspec::SoapAccessors
|
24
|
+
extend Forwardable
|
25
|
+
|
26
|
+
delegate [:operations] => :client
|
27
|
+
|
28
|
+
# Savon client used to make SOAP calls
|
29
|
+
attr_accessor :client
|
30
|
+
# SOAP Operation to use by default
|
31
|
+
attr_accessor :operation
|
32
|
+
|
33
|
+
# Attributes set at the root XML element of SOAP request
|
34
|
+
def request_root_attributes
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Options to log xml request and response
|
39
|
+
def logging_options
|
40
|
+
{
|
41
|
+
log: true, # See request and response. (Put this in traffic file)
|
42
|
+
log_level: :debug,
|
43
|
+
logger: Soaspec::SpecLogger.create,
|
44
|
+
pretty_print_xml: true # Prints XML pretty
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Default Savon options. See http://savonrb.com/version2/globals.html for details
|
49
|
+
# @return [Hash] Default Savon options for all BasicSoapHandler
|
50
|
+
def default_options
|
51
|
+
{
|
52
|
+
ssl_verify_mode: :none, # Easier for testing. Not so secure
|
53
|
+
follow_redirects: true, # Necessary for many API calls
|
54
|
+
soap_version: 2, # use SOAP 1.2. You will get 415 error if this is incorrect
|
55
|
+
raise_errors: false # HTTP errors not cause failure as often negative test scenarios expect not 200 response
|
56
|
+
# Things could go wrong if not set properly
|
57
|
+
# env_namespace: :soap, # Change environment namespace
|
58
|
+
# namespace_identifier: :tst, # Change namespace element
|
59
|
+
# element_form_default: :qualified # Populate each element with namespace
|
60
|
+
# namespace: 'http://Extended_namespace.xsd' change root namespace
|
61
|
+
# basic_auth: 'user', 'password'
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Add values to here when extending this class to have default Savon options.
|
66
|
+
# See http://savonrb.com/version2/globals.html for details
|
67
|
+
# @return [Hash] Savon options adding to & overriding defaults
|
68
|
+
def savon_options
|
69
|
+
{
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Setup object to handle communicating with a particular SOAP WSDL
|
74
|
+
# @param [Hash] options Options defining SOAP request. WSDL, authentication, see http://savonrb.com/version2/globals.html for list of options
|
75
|
+
def initialize(name = self.class.to_s, options = {})
|
76
|
+
@default_hash = {}
|
77
|
+
@request_option = :hash
|
78
|
+
if name.is_a?(Hash) && options == {} # If name is not set
|
79
|
+
options = name
|
80
|
+
name = self.class.to_s
|
81
|
+
end
|
82
|
+
super
|
83
|
+
set_remove_key(options, :operation)
|
84
|
+
set_remove_key(options, :default_hash)
|
85
|
+
set_remove_key(options, :template_name)
|
86
|
+
merged_options = Soaspec.log_api_traffic? ? default_options.merge(logging_options) : default_options
|
87
|
+
merged_options.merge! savon_options
|
88
|
+
merged_options.merge!(options)
|
89
|
+
self.client = Savon.client(merged_options)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Used in making request via hash or in template via Erb
|
93
|
+
def request_body_params(request_parameters)
|
94
|
+
test_values = request_parameters[:body] || request_parameters
|
95
|
+
test_values.transform_keys_to_symbols if Soaspec.always_use_keys?
|
96
|
+
end
|
97
|
+
|
98
|
+
# Used in together with Exchange request that passes such override parameters
|
99
|
+
# @param [Hash] request_parameters Parameters used to overwrite defaults in request
|
100
|
+
def make_request(request_parameters)
|
101
|
+
test_values = request_body_params request_parameters
|
102
|
+
begin
|
103
|
+
if @request_option == :template
|
104
|
+
request_body = File.read('template/' + template_name)
|
105
|
+
render_body = ERB.new(request_body).result(binding)
|
106
|
+
client.call(operation, xml: render_body) # Call the SOAP operation with the request XML provided
|
107
|
+
elsif @request_option == :hash
|
108
|
+
client.call(operation, message: @default_hash.merge(test_values), attributes: request_root_attributes)
|
109
|
+
end
|
110
|
+
rescue Savon::HTTPError => e
|
111
|
+
e
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param [Hash] format Format of expected result
|
116
|
+
# @return [Object] Generic body to be displayed in error messages
|
117
|
+
def response_body(response, format: :hash)
|
118
|
+
case format
|
119
|
+
when :hash
|
120
|
+
response.body
|
121
|
+
when :raw
|
122
|
+
response.xml
|
123
|
+
else
|
124
|
+
response.body
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [Boolean] Whether the request found the desired value or not
|
129
|
+
def found?(response)
|
130
|
+
status_code_for(response) != 404
|
131
|
+
end
|
132
|
+
|
133
|
+
# Response status code for response. '200' indicates a success
|
134
|
+
# @param [Savon::Response] response
|
135
|
+
# @return [Integer] Status code
|
136
|
+
def status_code_for(response)
|
137
|
+
response.http.code
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return [Boolean] Whether response includes provided string within it
|
141
|
+
def include_in_body?(response, expected)
|
142
|
+
response.to_xml.to_s.include? expected
|
143
|
+
end
|
144
|
+
|
145
|
+
# @param [Symbol] expected
|
146
|
+
# @return [Boolean] Whether response body contains expected key
|
147
|
+
def include_key?(response, expected)
|
148
|
+
body = response.body
|
149
|
+
body.extend Hashie::Extensions::DeepFind
|
150
|
+
!body.deep_find_all(expected).empty?
|
151
|
+
end
|
152
|
+
|
153
|
+
# Convert all XML nodes to lowercase
|
154
|
+
# @param [Nokogiri::XML::Document]
|
155
|
+
def convert_to_lower_case(xml_doc)
|
156
|
+
xml_doc.traverse do |node|
|
157
|
+
node.name = node.name.downcase if node.kind_of?(Nokogiri::XML::Element)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the value at the provided xpath
|
162
|
+
# @param [Savon::Response] response
|
163
|
+
# @param [String] xpath
|
164
|
+
# @return [Enumerable] Elements found through Xpath
|
165
|
+
def xpath_elements_for(response: nil, xpath: nil, attribute: nil)
|
166
|
+
raise ArgumentError('response and xpath must be passed to method') unless response && xpath
|
167
|
+
xpath = "//*[@#{attribute}]" unless attribute.nil?
|
168
|
+
xpath = '//' + xpath if xpath[0] != '/'
|
169
|
+
temp_doc = response.doc.dup
|
170
|
+
convert_to_lower_case(temp_doc) if convert_to_lower?
|
171
|
+
if strip_namespaces? && !xpath.include?(':')
|
172
|
+
temp_doc.remove_namespaces!
|
173
|
+
temp_doc.xpath(xpath)
|
174
|
+
else
|
175
|
+
temp_doc.xpath(xpath, temp_doc.collect_namespaces)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Based on a exchange, return the value at the provided xpath
|
180
|
+
# If the path does not begin with a '/', a '//' is added to it
|
181
|
+
# @param [Savon::Response] response
|
182
|
+
# @param [String] path Xpath
|
183
|
+
# @param [String] attribute Generic attribute to find. Will override path
|
184
|
+
# @return [String] Value at Xpath
|
185
|
+
def value_from_path(response, path, attribute: nil)
|
186
|
+
results = xpath_elements_for(response: response, xpath: path, attribute: attribute)
|
187
|
+
raise NoElementAtPath, "No value at Xpath '#{path}' in XML #{response.doc}" if results.empty?
|
188
|
+
return results.first.inner_text if attribute.nil?
|
189
|
+
results.first.attributes[attribute].inner_text
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Enumerable] List of values returned from path
|
193
|
+
def values_from_path(response, path, attribute: nil)
|
194
|
+
xpath_elements_for(response: response, xpath: path, attribute: attribute).map(&:inner_text)
|
195
|
+
end
|
196
|
+
|
197
|
+
# alias elements xpath_elements_for
|
198
|
+
|
199
|
+
# @return [Boolean] Whether any of the keys of the Body Hash include value
|
200
|
+
def include_value?(response, expected_value)
|
201
|
+
response.body.include_value?(expected_value)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Hash of response body
|
205
|
+
def to_hash(response)
|
206
|
+
response.body
|
207
|
+
end
|
208
|
+
|
209
|
+
# Convenience methods for once off usage of a SOAP request
|
210
|
+
class << self
|
211
|
+
|
212
|
+
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
213
|
+
# @param [Object] method_name Name of method not defined
|
214
|
+
# @param [Object] args Arguments passed to method
|
215
|
+
# @param [Object] block
|
216
|
+
def method_missing(method_name, *args, &block)
|
217
|
+
tmp_class = new(method_name)
|
218
|
+
operations = tmp_class.operations
|
219
|
+
if operations.include? method_name
|
220
|
+
tmp_class.operation = method_name
|
221
|
+
exchange = Exchange.new(method_name, *args)
|
222
|
+
exchange.exchange_handler = tmp_class
|
223
|
+
exchange
|
224
|
+
else
|
225
|
+
super
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def respond_to_missing?(method_name, *args)
|
230
|
+
tmp_class = new(args)
|
231
|
+
operations = tmp_class.operations
|
232
|
+
operations.include?(method_name) || super
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
237
|
end
|