lib/soaspec/exchange.rb in soaspec-0.1.6 vs lib/soaspec/exchange.rb in soaspec-0.1.7
- old
+ new
@@ -1,236 +1,236 @@
-require_relative '../soaspec'
-
-# Convenience methods to set Exchange specific properties
-module ExchangeAccessors
-
- # Set default exchange handler for this exchange
- # This is helpful for when you need a new exchange handler created for each exchange
- def default_handler(handler_class, name = handler_class.to_s, params = '')
- define_method('default_handler_used') do
- params_used = Hash[params.map do |k, param|
- [k, param.is_a?(String) ? ERB.new(param).result(binding) : param]
- end]
- handler_class.new name, params_used
- end
- end
-
- # Set retry_for_success to true, retrying response until a successful status code is returned
- def expect_positive_status(retry_count: 3)
- define_method('retry_count') do
- retry_count
- end
- define_method('retry_for_success?') do
- true
- end
- end
-
-end
-
-# This represents a request / response pair
-# Essentially, params in the exchange that are set are related to the request
-# What is returned is related to the response
-class Exchange
- extend ExchangeAccessors
-
- # Instance of ExchangeHandler for which this exchange is made
- attr_accessor :exchange_handler
- # How many times to retry for a success
- attr_accessor :retry_count
- # Name used for displaying class
- attr_accessor :test_name
- # Expect Factory to fail upon trying to create
- attr_writer :fail_factory
-
-
- def values_from_path(path, attribute: nil)
- exchange_handler.values_from_path(response, path, attribute: attribute)
- end
-
- # Set retry for success variable to true so that request will be retried
- # for retry_count until it's true
- def retry_for_success
- @retry_for_success = true
- self
- end
-
- # @return [Bool] Whether to keep making request until success code reached
- def retry_for_success?
- @retry_for_success
- end
-
- # @return [Boolean] Soaspec::ExchangeHandler used by this exchange
- def default_handler_used
- nil
- end
-
- # @param [String] element Element to define methods for
- def methods_for_element(element)
- element_name = element.to_s.split('__custom_path_').last
- define_singleton_method(element_name) do
- exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
- end
- define_singleton_method("#{element_name}?") do
- begin
- __send__ element_name
- true
- rescue NoElementAtPath
- false
- end
- end
- end
-
- # @param [Symbol, String] name Name shown in RSpec run
- # @param [Hash] override_parameters Parameters to override for default params
- def initialize(name = self.class.to_s, override_parameters = {})
- self.test_name ||= name.to_s
- # As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
- @exchange_handler ||= default_handler_used || Soaspec.api_handler
- raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
- @fail_factory = nil
- @override_parameters = override_parameters
- @retry_for_success = false
- self.retry_count = 3
- @exchange_handler.elements.each { |element| methods_for_element(element) }
- end
-
- # Specify a url to add onto the base_url of the ExchangeHandler used
- # @param [String] url Url to add onto the base_url of the ExchangeHandler used
- def suburl=(url)
- @override_parameters[:suburl] = url
- end
-
- # Specify HTTP method to use. Default is :post
- # @param [Symbol] method HTTP method. E.g, :get, :patch
- def method=(method)
- @override_parameters[:method] = method
- end
-
- # Make request to handler with parameters defined
- # Will retry until success code reached if retry_for_success? is set
- # @return [Response] Response from Api handler
- def make_request
- Soaspec::SpecLogger.info 'Example ' + test_name
- request_params = @override_parameters
- (1..retry_count).each do |count|
- response = exchange_handler.make_request(request_params)
- return response unless retry_for_success?
- return response if (200..299).cover? @exchange_handler.status_code_for(response)
- sleep 0.5
- break response if count == retry_count
- end
- end
-
- # Stores a value in the api handler that can be accessed by the provided name
- # @param [Symbol] name Name of method to use to access this value within handler
- # @param [String] value Path to value to store
- def store(name, value)
- exchange_handler.store(name, self[value])
- end
-
- # Retrieve the stored value from the Api Handler
- # @param [String, Symbol] name Name of value to retrieve
- # @return [Object] value from the Api Handler stored previously
- def retrieve(name)
- method = '__stored_val__' + name.to_s
- raise ArgumentError('Value not stored at ') unless exchange_handler.respond_to? method
- exchange_handler.send(method)
- end
-
- # Name describing this class when used with `RSpec.describe`
- # This will make the request and store the response
- # @return [String] Name given when initializing
- def to_s
- test_name
- end
-
- # Returns response object from Api. Will make the request if not made and then cache it for later on
- # For example for SOAP it will be a Savon response
- # response.body (body of response as Hash)
- # response.header (head of response as Hash)
- def response
- Soaspec.last_exchange = self
- @response ||= make_request
- end
-
- alias call response
-
- # Get status code from api class. This is http response for Web Api
- # @return [Integer] Status code from api class
- def status_code
- exchange_handler.status_code_for(response)
- end
-
- # Dummy request used to make a request without verifying it and ignoring WSDL errors
- # @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
- def dummy_request
- make_request
- true
- rescue Savon::HTTPError
- puts 'Resolver error'
- # This seems to occur first time IP address asks for WSDL
- true
- end
-
- # @return [Boolean] Whether an element exists at the path
- def element?(path)
- [path]
- true
- rescue NoElementAtPath
- false
- end
-
- # Extract value from path api class
- # @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
- # @return [String] Value at path
- def [](path)
- exchange_handler.value_from_path(response, path.to_s)
- end
-
- # Set a parameter request in the request body.
- # Can be used to build a request over several steps (e.g Cucumber)
- # Will be used with FactoryBot
- def []=(key, value)
- @override_parameters[:body] ||= {}
- @override_parameters[:body][key] = value
- end
-
- # Implement undefined setter with []= for FactoryBot to use without needing to define params to set
- # @param [Object] method_name Name of method not defined
- # @param [Object] args Arguments passed to method
- # @param [Object] block
- def method_missing(method_name, *args, &block)
- set_value = args.first
- if method_name[-1] == '=' # A setter method
- getter_name = method_name[0..-2]
- if set_value.class < Exchange # This would be prerequisite exchange
- define_singleton_method(getter_name) do
- set_value
- end
- self[getter_name] = set_value.id if set_value.respond_to?(:id)
- else
- self[getter_name] = set_value
- end
- else
- super
- end
- end
-
- # Used for setters that are not defined
- def respond_to_missing?(method_name, *args)
- method_name[-1] == '=' || super
- end
-
- # Makes request, caching the response and returning self
- # Used by FactoryBot
- # @return [Self]
- def save!
- @retry_for_success = @fail_factory ? false : true
- call
- self
- end
-
- def to_hash
- exchange_handler.to_hash(response)
- end
-
+require_relative '../soaspec'
+
+# Convenience methods to set Exchange specific properties
+module ExchangeAccessors
+
+ # Set default exchange handler for this exchange
+ # This is helpful for when you need a new exchange handler created for each exchange
+ def default_handler(handler_class, name = handler_class.to_s, params = '')
+ define_method('default_handler_used') do
+ params_used = Hash[params.map do |k, param|
+ [k, param.is_a?(String) ? ERB.new(param).result(binding) : param]
+ end]
+ handler_class.new name, params_used
+ end
+ end
+
+ # Set retry_for_success to true, retrying response until a successful status code is returned
+ def expect_positive_status(retry_count: 3)
+ define_method('retry_count') do
+ retry_count
+ end
+ define_method('retry_for_success?') do
+ true
+ end
+ end
+
+end
+
+# This represents a request / response pair
+# Essentially, params in the exchange that are set are related to the request
+# What is returned is related to the response
+class Exchange
+ extend ExchangeAccessors
+
+ # Instance of ExchangeHandler for which this exchange is made
+ attr_accessor :exchange_handler
+ # How many times to retry for a success
+ attr_accessor :retry_count
+ # Name used for displaying class
+ attr_accessor :test_name
+ # Expect Factory to fail upon trying to create
+ attr_writer :fail_factory
+
+
+ def values_from_path(path, attribute: nil)
+ exchange_handler.values_from_path(response, path, attribute: attribute)
+ end
+
+ # Set retry for success variable to true so that request will be retried
+ # for retry_count until it's true
+ def retry_for_success
+ @retry_for_success = true
+ self
+ end
+
+ # @return [Bool] Whether to keep making request until success code reached
+ def retry_for_success?
+ @retry_for_success
+ end
+
+ # @return [Boolean] Soaspec::ExchangeHandler used by this exchange
+ def default_handler_used
+ nil
+ end
+
+ # @param [String] element Element to define methods for
+ def methods_for_element(element)
+ element_name = element.to_s.split('__custom_path_').last
+ define_singleton_method(element_name) do
+ exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
+ end
+ define_singleton_method("#{element_name}?") do
+ begin
+ __send__ element_name
+ true
+ rescue NoElementAtPath
+ false
+ end
+ end
+ end
+
+ # @param [Symbol, String] name Name shown in RSpec run
+ # @param [Hash] override_parameters Parameters to override for default params
+ def initialize(name = self.class.to_s, override_parameters = {})
+ self.test_name ||= name.to_s
+ # As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
+ @exchange_handler ||= default_handler_used || Soaspec.api_handler
+ raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
+ @fail_factory = nil
+ @override_parameters = override_parameters
+ @retry_for_success = false
+ self.retry_count = 3
+ @exchange_handler.elements.each { |element| methods_for_element(element) }
+ end
+
+ # Specify a url to add onto the base_url of the ExchangeHandler used
+ # @param [String] url Url to add onto the base_url of the ExchangeHandler used
+ def suburl=(url)
+ @override_parameters[:suburl] = url
+ end
+
+ # Specify HTTP method to use. Default is :post
+ # @param [Symbol] method HTTP method. E.g, :get, :patch
+ def method=(method)
+ @override_parameters[:method] = method
+ end
+
+ # Make request to handler with parameters defined
+ # Will retry until success code reached if retry_for_success? is set
+ # @return [Response] Response from Api handler
+ def make_request
+ Soaspec::SpecLogger.info 'Example ' + test_name
+ request_params = @override_parameters
+ (1..retry_count).each do |count|
+ response = exchange_handler.make_request(request_params)
+ return response unless retry_for_success?
+ return response if (200..299).cover? @exchange_handler.status_code_for(response)
+ sleep 0.5
+ break response if count == retry_count
+ end
+ end
+
+ # Stores a value in the api handler that can be accessed by the provided name
+ # @param [Symbol] name Name of method to use to access this value within handler
+ # @param [String] value Path to value to store
+ def store(name, value)
+ exchange_handler.store(name, self[value])
+ end
+
+ # Retrieve the stored value from the Api Handler
+ # @param [String, Symbol] name Name of value to retrieve
+ # @return [Object] value from the Api Handler stored previously
+ def retrieve(name)
+ method = '__stored_val__' + name.to_s
+ raise ArgumentError('Value not stored at ') unless exchange_handler.respond_to? method
+ exchange_handler.send(method)
+ end
+
+ # Name describing this class when used with `RSpec.describe`
+ # This will make the request and store the response
+ # @return [String] Name given when initializing
+ def to_s
+ test_name
+ end
+
+ # Returns response object from Api. Will make the request if not made and then cache it for later on
+ # For example for SOAP it will be a Savon response
+ # response.body (body of response as Hash)
+ # response.header (head of response as Hash)
+ def response
+ Soaspec.last_exchange = self
+ @response ||= make_request
+ end
+
+ alias call response
+
+ # Get status code from api class. This is http response for Web Api
+ # @return [Integer] Status code from api class
+ def status_code
+ exchange_handler.status_code_for(response)
+ end
+
+ # Dummy request used to make a request without verifying it and ignoring WSDL errors
+ # @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
+ def dummy_request
+ make_request
+ true
+ rescue Savon::HTTPError
+ puts 'Resolver error'
+ # This seems to occur first time IP address asks for WSDL
+ true
+ end
+
+ # @return [Boolean] Whether an element exists at the path
+ def element?(path)
+ [path]
+ true
+ rescue NoElementAtPath
+ false
+ end
+
+ # Extract value from path api class
+ # @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
+ # @return [String] Value at path
+ def [](path)
+ exchange_handler.value_from_path(response, path.to_s)
+ end
+
+ # Set a parameter request in the request body.
+ # Can be used to build a request over several steps (e.g Cucumber)
+ # Will be used with FactoryBot
+ def []=(key, value)
+ @override_parameters[:body] ||= {}
+ @override_parameters[:body][key] = value
+ end
+
+ # Implement undefined setter with []= for FactoryBot to use without needing to define params to set
+ # @param [Object] method_name Name of method not defined
+ # @param [Object] args Arguments passed to method
+ # @param [Object] block
+ def method_missing(method_name, *args, &block)
+ set_value = args.first
+ if method_name[-1] == '=' # A setter method
+ getter_name = method_name[0..-2]
+ if set_value.class < Exchange # This would be prerequisite exchange
+ define_singleton_method(getter_name) do
+ set_value
+ end
+ self[getter_name] = set_value.id if set_value.respond_to?(:id)
+ else
+ self[getter_name] = set_value
+ end
+ else
+ super
+ end
+ end
+
+ # Used for setters that are not defined
+ def respond_to_missing?(method_name, *args)
+ method_name[-1] == '=' || super
+ end
+
+ # Makes request, caching the response and returning self
+ # Used by FactoryBot
+ # @return [Self]
+ def save!
+ @retry_for_success = @fail_factory ? false : true
+ call
+ self
+ end
+
+ def to_hash
+ exchange_handler.to_hash(response)
+ end
+
end
\ No newline at end of file