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,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(File.join(Soaspec.template_folder, 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(File.join(Soaspec.template_folder, 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
|