soaspec 0.2.10 → 0.2.11
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 +4 -4
- data/ChangeLog +4 -0
- data/images/basic_demo.gif +0 -0
- data/lib/soaspec.rb +1 -1
- data/lib/soaspec/demo.rb +1 -1
- data/lib/soaspec/exchange/exchange.rb +97 -0
- data/lib/soaspec/exchange/exchange_extractor.rb +59 -0
- data/lib/soaspec/exchange/exchange_properties.rb +29 -0
- data/lib/soaspec/exchange/exchange_repeater.rb +19 -0
- data/lib/soaspec/exchange/request_builder.rb +57 -0
- data/lib/soaspec/exchange/variable_storer.rb +22 -0
- data/lib/soaspec/exchange_handlers/handler_accessors.rb +2 -1
- data/lib/soaspec/exchange_handlers/rest_parameters.rb +1 -1
- data/lib/soaspec/o_auth2.rb +12 -0
- data/lib/soaspec/test_server/invoices.rb +2 -1
- data/lib/soaspec/version.rb +1 -1
- metadata +8 -4
- data/lib/soaspec/exchange.rb +0 -236
- data/lib/soaspec/exchange_properties.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4316417650edcdef9d66fb391ff90736a400dc2
|
4
|
+
data.tar.gz: 163b3ca2c9a547915693d33a7e7147dbc079cea6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a58886e537a7e063f4977a184cac67d32ffe4827d4331315475d780450d0025bf86a000978457a0d5b52f1361e54496d1661f70904f6aa84f9ada7a8d300f12
|
7
|
+
data.tar.gz: 41c07147d1db749aab3b3c4dfbfa638b46e46297ddbdc39c9f8eef0eb27bc9ad47dc347920c960fa1069236641aa2acd58d4619c6f46f0d775783b933b8dcbfb
|
data/ChangeLog
CHANGED
data/images/basic_demo.gif
CHANGED
Binary file
|
data/lib/soaspec.rb
CHANGED
@@ -15,7 +15,7 @@ require 'soaspec/template_reader'
|
|
15
15
|
require 'soaspec/exchange_handlers/soap_handler'
|
16
16
|
require 'soaspec/exchange_handlers/exchange_handler'
|
17
17
|
require 'soaspec/exchange_handlers/rest_methods'
|
18
|
-
require 'soaspec/exchange'
|
18
|
+
require 'soaspec/exchange/exchange'
|
19
19
|
require 'soaspec/matchers'
|
20
20
|
require 'soaspec/soaspec_shared_examples'
|
21
21
|
require 'soaspec/core_ext/hash'
|
data/lib/soaspec/demo.rb
CHANGED
@@ -0,0 +1,97 @@
|
|
1
|
+
require_relative '../../soaspec'
|
2
|
+
require_relative 'exchange_properties'
|
3
|
+
require_relative 'exchange_extractor'
|
4
|
+
require_relative 'request_builder'
|
5
|
+
require_relative 'exchange_repeater'
|
6
|
+
require_relative 'variable_storer'
|
7
|
+
|
8
|
+
# This represents a request / response pair
|
9
|
+
# Essentially, params in the exchange that are set are related to the request
|
10
|
+
# What is returned is related to the response
|
11
|
+
class Exchange
|
12
|
+
extend Soaspec::ExchangeProperties
|
13
|
+
include Soaspec::ExchangeExtractor
|
14
|
+
include Soaspec::RequestBuilder
|
15
|
+
include Soaspec::ExchangeRepeater
|
16
|
+
include Soaspec::VariableStorer
|
17
|
+
|
18
|
+
# Instance of ExchangeHandler for which this exchange is made
|
19
|
+
attr_accessor :exchange_handler
|
20
|
+
# How many times to retry for a success
|
21
|
+
attr_accessor :retry_count
|
22
|
+
# Name used for displaying class
|
23
|
+
attr_accessor :test_name
|
24
|
+
# Expect Factory to fail upon trying to create
|
25
|
+
attr_writer :fail_factory
|
26
|
+
# Parameters to override for default params
|
27
|
+
attr_accessor :override_parameters
|
28
|
+
|
29
|
+
# Set retry for success variable to true so that request will be retried
|
30
|
+
# for retry_count until it's true
|
31
|
+
def retry_for_success
|
32
|
+
@retry_for_success = true
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Bool] Whether to keep making request until success code reached
|
37
|
+
def retry_for_success?
|
38
|
+
@retry_for_success
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Boolean] Soaspec::ExchangeHandler used by this exchange
|
42
|
+
def default_handler_used
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param [Symbol, String] name Name shown in RSpec run
|
47
|
+
# @param [Hash] override_parameters Parameters to override for default params
|
48
|
+
def initialize(name = self.class.to_s, override_parameters = {})
|
49
|
+
self.test_name ||= name.to_s
|
50
|
+
# As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
|
51
|
+
@exchange_handler ||= default_handler_used || Soaspec.api_handler
|
52
|
+
raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
|
53
|
+
|
54
|
+
@fail_factory = nil
|
55
|
+
@override_parameters = override_parameters
|
56
|
+
@retry_for_success = false
|
57
|
+
self.retry_count = 3
|
58
|
+
@exchange_handler.elements.each { |element| methods_for_element(element) }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Make request to handler with parameters defined
|
62
|
+
# Will retry until success code reached if retry_for_success? is set
|
63
|
+
# @return [Response] Response from Api handler
|
64
|
+
def make_request
|
65
|
+
Soaspec::SpecLogger.info 'Example ' + test_name
|
66
|
+
request_params = @override_parameters
|
67
|
+
(1..retry_count).each do |count|
|
68
|
+
response = exchange_handler.make_request(request_params)
|
69
|
+
return response unless retry_for_success?
|
70
|
+
return response if (200..299).cover? exchange_handler.status_code_for(response)
|
71
|
+
|
72
|
+
sleep 0.5
|
73
|
+
break response if count == retry_count
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Name describing this class when used with `RSpec.describe`
|
78
|
+
# This will make the request and store the response
|
79
|
+
# @return [String] Name given when initializing
|
80
|
+
def to_s
|
81
|
+
test_name
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns response object from Api. Will make the request if not made and then cache it for later on
|
85
|
+
# @example For SOAP it will be a Savon response
|
86
|
+
# response.body (body of response as Hash)
|
87
|
+
# response.header (head of response as Hash)
|
88
|
+
# @example For REST it will be a RestClient::Response
|
89
|
+
def response
|
90
|
+
Soaspec.last_exchange = self
|
91
|
+
@response ||= make_request
|
92
|
+
@response.define_singleton_method(:exchange) { Soaspec.last_exchange } unless @response.respond_to?(:exchange)
|
93
|
+
@response
|
94
|
+
end
|
95
|
+
|
96
|
+
alias call response
|
97
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Soaspec
|
2
|
+
# Methods for extracting aspects of the traffic for a request / response
|
3
|
+
# in an exchange from the ExchangeHandler that it's tied to
|
4
|
+
module ExchangeExtractor
|
5
|
+
# @param [String] path XPath, JSONPath to extract value
|
6
|
+
# @param [String] attribute Attribute to obtain from XML element
|
7
|
+
# @return [Array] List of values found at path
|
8
|
+
def values_from_path(path, attribute: nil)
|
9
|
+
exchange_handler.values_from_path(response, path, attribute: attribute)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Request of API call. Either intended request or actual request
|
13
|
+
def request
|
14
|
+
exchange_handler.request(@response)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get status code from api class. This is http response for Web Api
|
18
|
+
# @return [Integer] Status code from api class
|
19
|
+
def status_code
|
20
|
+
exchange_handler.status_code_for(response)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Boolean] Whether an element exists at the path
|
24
|
+
def element?(path)
|
25
|
+
self[path]
|
26
|
+
true
|
27
|
+
rescue NoElementAtPath
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
# Extract value from path api class
|
32
|
+
# @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
|
33
|
+
# @return [String] Value at path
|
34
|
+
def [](path)
|
35
|
+
exchange_handler.value_from_path(response, path.to_s)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [String] element Element to define methods for
|
39
|
+
def methods_for_element(element)
|
40
|
+
element_name = element.to_s.split('__custom_path_').last
|
41
|
+
define_singleton_method(element_name) do
|
42
|
+
exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
|
43
|
+
end
|
44
|
+
define_singleton_method("#{element_name}?") do
|
45
|
+
begin
|
46
|
+
__send__ element_name
|
47
|
+
true
|
48
|
+
rescue NoElementAtPath
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Hash] Hash representing the response of the API
|
55
|
+
def to_hash
|
56
|
+
exchange_handler.to_hash(response)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Soaspec
|
2
|
+
# Convenience methods to set Exchange specific properties
|
3
|
+
# Will be used when creating a subclass of Exchange
|
4
|
+
module ExchangeProperties
|
5
|
+
# Set default exchange handler for this exchange
|
6
|
+
# This is helpful for when you need a new exchange handler created for each exchange
|
7
|
+
# @param [Class] handler_class Class of ExchangeHandler to set Exchange to use
|
8
|
+
# @param [String] name Name to call handler when it's instantiated (Defaults to class name)
|
9
|
+
# @param [Hash] params Hash of parameters to set for instance of ExchangeHandler
|
10
|
+
def default_handler(handler_class, name = handler_class.to_s, params = '')
|
11
|
+
define_method('default_handler_used') do
|
12
|
+
params_used = Hash[params.map do |k, param|
|
13
|
+
[k, param.is_a?(String) ? ERB.new(param).result(binding) : param]
|
14
|
+
end]
|
15
|
+
handler_class.new name, params_used
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Set retry_for_success to true, retrying response until a successful status code is returned
|
20
|
+
def expect_positive_status(retry_count: 3)
|
21
|
+
define_method('retry_count') do
|
22
|
+
retry_count
|
23
|
+
end
|
24
|
+
define_method('retry_for_success?') do
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Soaspec
|
2
|
+
# Ways of repeating an exchange to reach a desired outcome
|
3
|
+
module ExchangeRepeater
|
4
|
+
# Wait until the passed block returns true
|
5
|
+
# @param [Hash] opts Options for this instance
|
6
|
+
# @option opts [Numeric] :timeout (5) Seconds to wait before timing out.
|
7
|
+
# @option opts [Numeric] :interval (0.2) Seconds to sleep between polls.
|
8
|
+
# @option opts [String] :message Exception message if timed out.
|
9
|
+
# @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Error::NoSuchElementError)
|
10
|
+
# @return [Self] Returns itself so operations can be done on the exchange after it's done waiting
|
11
|
+
def until(opts = {}, &script)
|
12
|
+
Soaspec::Wait.until(opts) do
|
13
|
+
@response = nil # Reset response so it can be made repeatedly
|
14
|
+
instance_eval(&script)
|
15
|
+
end
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Soaspec
|
2
|
+
# Methods to help build a Request
|
3
|
+
module RequestBuilder
|
4
|
+
# Specify a url to add onto the base_url of the ExchangeHandler used
|
5
|
+
# @param [String] url Url to add onto the base_url of the ExchangeHandler used
|
6
|
+
def suburl=(url)
|
7
|
+
@override_parameters[:suburl] = url
|
8
|
+
end
|
9
|
+
|
10
|
+
# Specify HTTP method to use. Default is :post
|
11
|
+
# @param [Symbol] method HTTP method. E.g, :get, :patch
|
12
|
+
def method=(method)
|
13
|
+
@override_parameters[:method] = method
|
14
|
+
end
|
15
|
+
|
16
|
+
# Set a parameter request in the request body.
|
17
|
+
# Can be used to build a request over several steps (e.g Cucumber)
|
18
|
+
# Will be used with FactoryBot
|
19
|
+
def []=(key, value)
|
20
|
+
@override_parameters[:body] ||= {}
|
21
|
+
@override_parameters[:body][key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
25
|
+
# @param [Object] method_name Name of method not defined
|
26
|
+
# @param [Object] args Arguments passed to method
|
27
|
+
# @param [Object] block
|
28
|
+
def method_missing(method_name, *args, &block)
|
29
|
+
set_value = args.first
|
30
|
+
if method_name[-1] == '=' # A setter method
|
31
|
+
getter_name = method_name[0..-2]
|
32
|
+
if set_value.class < Exchange # This would be prerequisite exchange
|
33
|
+
define_singleton_method(getter_name) { set_value }
|
34
|
+
self[getter_name] = set_value.id if set_value.respond_to?(:id)
|
35
|
+
else
|
36
|
+
self[getter_name] = set_value
|
37
|
+
end
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Used for setters that are not defined
|
44
|
+
def respond_to_missing?(method_name, *args)
|
45
|
+
method_name[-1] == '=' || super
|
46
|
+
end
|
47
|
+
|
48
|
+
# Makes request, caching the response and returning self
|
49
|
+
# Used by FactoryBot
|
50
|
+
# @return [Self]
|
51
|
+
def save!
|
52
|
+
@retry_for_success = @fail_factory ? false : true
|
53
|
+
call
|
54
|
+
self
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Soaspec
|
2
|
+
# Enables Exchange to store and retrieve variables so that one
|
3
|
+
# exchange can make assertions based on a previous one
|
4
|
+
module VariableStorer
|
5
|
+
# Stores a value in the api handler that can be accessed by the provided name
|
6
|
+
# @param [Symbol] name Name of method to use to access this value within handler
|
7
|
+
# @param [String] value Path to value to store
|
8
|
+
def store(name, value)
|
9
|
+
exchange_handler.store(name, self[value])
|
10
|
+
end
|
11
|
+
|
12
|
+
# Retrieve the stored value from the Api Handler
|
13
|
+
# @param [String, Symbol] name Name of value to retrieve
|
14
|
+
# @return [Object] value from the Api Handler stored previously
|
15
|
+
def retrieve(name)
|
16
|
+
method = '__stored_val__' + name.to_s
|
17
|
+
raise ArgumentError('Value not stored at ') unless exchange_handler.respond_to? method
|
18
|
+
|
19
|
+
exchange_handler.send(method)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -62,7 +62,8 @@ module Soaspec
|
|
62
62
|
# This will use the 'value_from_path' method which
|
63
63
|
# should be implemented by each ExchangeHandler
|
64
64
|
# @param [String, Symbol] name Method name used to access element
|
65
|
-
# @param [String, Symbol] path Path to find object (e.g, XPath, JSONPath)
|
65
|
+
# @param [String, Symbol] path Path to find object (e.g, XPath, JSONPath).
|
66
|
+
# For JSONPath a ',' can be put to get an element either path
|
66
67
|
def element(name, path)
|
67
68
|
define_method("__custom_path_#{name}") do |response|
|
68
69
|
value_from_path(response, path.to_s)
|
@@ -23,7 +23,7 @@ module Soaspec
|
|
23
23
|
# @!method access_token Retrieve OAuth2 access token
|
24
24
|
define_method('access_token') { oauth_obj.access_token }
|
25
25
|
# @!method instance_url Retrieve instance url from OAuth request
|
26
|
-
define_method('instance_url') { oauth_obj.
|
26
|
+
define_method('instance_url') { oauth_obj.instance_url }
|
27
27
|
end
|
28
28
|
|
29
29
|
# Pass path to YAML file containing OAuth2 parameters
|
data/lib/soaspec/o_auth2.rb
CHANGED
@@ -7,6 +7,8 @@ module Soaspec
|
|
7
7
|
@refresh_token = :always
|
8
8
|
# List of access tokens. They are mapped according to the OAuth parameters used
|
9
9
|
@access_tokens = {}
|
10
|
+
# List of instance URLs. They are mapped according to the OAuth parameters used
|
11
|
+
@instance_urls = {}
|
10
12
|
class << self
|
11
13
|
# Default token url used across entire suite
|
12
14
|
attr_accessor :token_url
|
@@ -17,6 +19,8 @@ module Soaspec
|
|
17
19
|
attr_accessor :refresh_token
|
18
20
|
# @attr [Hash] access_tokens List of access tokens. They are mapped according to the OAuth parameters used
|
19
21
|
attr_accessor :access_tokens
|
22
|
+
# List of URLs to that define the instance of an application
|
23
|
+
attr_accessor :instance_urls
|
20
24
|
end
|
21
25
|
|
22
26
|
# @attr [Hash] OAuth parameters
|
@@ -47,6 +51,14 @@ module Soaspec
|
|
47
51
|
Soaspec::SpecLogger.info request_message
|
48
52
|
end
|
49
53
|
|
54
|
+
# Retrieve instance_url according to access token response.
|
55
|
+
# Some applications have a different instance
|
56
|
+
# It's assumed this will be constant for a set of oauth parameters
|
57
|
+
# @return [String] Instance url
|
58
|
+
def instance_url
|
59
|
+
Soaspec::OAuth2.instance_urls[params] ||= response['instance_url']
|
60
|
+
end
|
61
|
+
|
50
62
|
# @return [String] Existing or new access token, dependent on refresh_token attribute
|
51
63
|
def access_token
|
52
64
|
case Soaspec::OAuth2.refresh_token
|
@@ -17,7 +17,8 @@ module Soaspec
|
|
17
17
|
{
|
18
18
|
access_token: 'TEST_TOKENiIsImtpZCI6IlRFU1QifQ.AAAABBBBRfaWQiOiJhYWQ5MjY3SIMULATE_LARGE_TOKEN3MmM5OGQ5NGE2YTU5YSIsImV4cCI6MTUyNzU3MTY4Mywic2NvcGUiOltdfQ.3OmCdW7fLZMUST_BE_ABLE_TO_HANDLEgAGaJB0lFYyhaw',
|
19
19
|
token_type: 'Bearer',
|
20
|
-
expires_in: '86399'
|
20
|
+
expires_in: '86399',
|
21
|
+
instance_url: %w[http://this_is_my_instance http://this_is_second_instance].sample
|
21
22
|
}
|
22
23
|
end
|
23
24
|
end
|
data/lib/soaspec/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soaspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SamuelGarrattIQA
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -403,7 +403,12 @@ files:
|
|
403
403
|
- lib/soaspec/core_ext/hash.rb
|
404
404
|
- lib/soaspec/cucumber/generic_steps.rb
|
405
405
|
- lib/soaspec/demo.rb
|
406
|
-
- lib/soaspec/exchange.rb
|
406
|
+
- lib/soaspec/exchange/exchange.rb
|
407
|
+
- lib/soaspec/exchange/exchange_extractor.rb
|
408
|
+
- lib/soaspec/exchange/exchange_properties.rb
|
409
|
+
- lib/soaspec/exchange/exchange_repeater.rb
|
410
|
+
- lib/soaspec/exchange/request_builder.rb
|
411
|
+
- lib/soaspec/exchange/variable_storer.rb
|
407
412
|
- lib/soaspec/exchange_handlers/exchange_handler.rb
|
408
413
|
- lib/soaspec/exchange_handlers/handler_accessors.rb
|
409
414
|
- lib/soaspec/exchange_handlers/response_extractor.rb
|
@@ -413,7 +418,6 @@ files:
|
|
413
418
|
- lib/soaspec/exchange_handlers/rest_parameters.rb
|
414
419
|
- lib/soaspec/exchange_handlers/rest_parameters_defaults.rb
|
415
420
|
- lib/soaspec/exchange_handlers/soap_handler.rb
|
416
|
-
- lib/soaspec/exchange_properties.rb
|
417
421
|
- lib/soaspec/exe_helpers.rb
|
418
422
|
- lib/soaspec/generator/.rspec.erb
|
419
423
|
- lib/soaspec/generator/.travis.yml.erb
|
data/lib/soaspec/exchange.rb
DELETED
@@ -1,236 +0,0 @@
|
|
1
|
-
require_relative '../soaspec'
|
2
|
-
require_relative 'exchange_properties'
|
3
|
-
|
4
|
-
# This represents a request / response pair
|
5
|
-
# Essentially, params in the exchange that are set are related to the request
|
6
|
-
# What is returned is related to the response
|
7
|
-
class Exchange
|
8
|
-
extend ExchangeProperties
|
9
|
-
|
10
|
-
# Instance of ExchangeHandler for which this exchange is made
|
11
|
-
attr_accessor :exchange_handler
|
12
|
-
# How many times to retry for a success
|
13
|
-
attr_accessor :retry_count
|
14
|
-
# Name used for displaying class
|
15
|
-
attr_accessor :test_name
|
16
|
-
# Expect Factory to fail upon trying to create
|
17
|
-
attr_writer :fail_factory
|
18
|
-
# Parameters to override for default params
|
19
|
-
attr_accessor :override_parameters
|
20
|
-
|
21
|
-
def values_from_path(path, attribute: nil)
|
22
|
-
exchange_handler.values_from_path(response, path, attribute: attribute)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Set retry for success variable to true so that request will be retried
|
26
|
-
# for retry_count until it's true
|
27
|
-
def retry_for_success
|
28
|
-
@retry_for_success = true
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
# @return [Bool] Whether to keep making request until success code reached
|
33
|
-
def retry_for_success?
|
34
|
-
@retry_for_success
|
35
|
-
end
|
36
|
-
|
37
|
-
# @return [Boolean] Soaspec::ExchangeHandler used by this exchange
|
38
|
-
def default_handler_used
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
|
42
|
-
# @param [String] element Element to define methods for
|
43
|
-
def methods_for_element(element)
|
44
|
-
element_name = element.to_s.split('__custom_path_').last
|
45
|
-
define_singleton_method(element_name) do
|
46
|
-
exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
|
47
|
-
end
|
48
|
-
define_singleton_method("#{element_name}?") do
|
49
|
-
begin
|
50
|
-
__send__ element_name
|
51
|
-
true
|
52
|
-
rescue NoElementAtPath
|
53
|
-
false
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# @param [Symbol, String] name Name shown in RSpec run
|
59
|
-
# @param [Hash] override_parameters Parameters to override for default params
|
60
|
-
def initialize(name = self.class.to_s, override_parameters = {})
|
61
|
-
self.test_name ||= name.to_s
|
62
|
-
# As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
|
63
|
-
@exchange_handler ||= default_handler_used || Soaspec.api_handler
|
64
|
-
raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
|
65
|
-
|
66
|
-
@fail_factory = nil
|
67
|
-
@override_parameters = override_parameters
|
68
|
-
@retry_for_success = false
|
69
|
-
self.retry_count = 3
|
70
|
-
@exchange_handler.elements.each { |element| methods_for_element(element) }
|
71
|
-
end
|
72
|
-
|
73
|
-
# Specify a url to add onto the base_url of the ExchangeHandler used
|
74
|
-
# @param [String] url Url to add onto the base_url of the ExchangeHandler used
|
75
|
-
def suburl=(url)
|
76
|
-
@override_parameters[:suburl] = url
|
77
|
-
end
|
78
|
-
|
79
|
-
# Specify HTTP method to use. Default is :post
|
80
|
-
# @param [Symbol] method HTTP method. E.g, :get, :patch
|
81
|
-
def method=(method)
|
82
|
-
@override_parameters[:method] = method
|
83
|
-
end
|
84
|
-
|
85
|
-
# Make request to handler with parameters defined
|
86
|
-
# Will retry until success code reached if retry_for_success? is set
|
87
|
-
# @return [Response] Response from Api handler
|
88
|
-
def make_request
|
89
|
-
Soaspec::SpecLogger.info 'Example ' + test_name
|
90
|
-
request_params = @override_parameters
|
91
|
-
(1..retry_count).each do |count|
|
92
|
-
response = exchange_handler.make_request(request_params)
|
93
|
-
return response unless retry_for_success?
|
94
|
-
return response if (200..299).cover? @exchange_handler.status_code_for(response)
|
95
|
-
|
96
|
-
sleep 0.5
|
97
|
-
break response if count == retry_count
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Stores a value in the api handler that can be accessed by the provided name
|
102
|
-
# @param [Symbol] name Name of method to use to access this value within handler
|
103
|
-
# @param [String] value Path to value to store
|
104
|
-
def store(name, value)
|
105
|
-
exchange_handler.store(name, self[value])
|
106
|
-
end
|
107
|
-
|
108
|
-
# Retrieve the stored value from the Api Handler
|
109
|
-
# @param [String, Symbol] name Name of value to retrieve
|
110
|
-
# @return [Object] value from the Api Handler stored previously
|
111
|
-
def retrieve(name)
|
112
|
-
method = '__stored_val__' + name.to_s
|
113
|
-
raise ArgumentError('Value not stored at ') unless exchange_handler.respond_to? method
|
114
|
-
|
115
|
-
exchange_handler.send(method)
|
116
|
-
end
|
117
|
-
|
118
|
-
# Name describing this class when used with `RSpec.describe`
|
119
|
-
# This will make the request and store the response
|
120
|
-
# @return [String] Name given when initializing
|
121
|
-
def to_s
|
122
|
-
test_name
|
123
|
-
end
|
124
|
-
|
125
|
-
# Returns response object from Api. Will make the request if not made and then cache it for later on
|
126
|
-
# @example For SOAP it will be a Savon response
|
127
|
-
# response.body (body of response as Hash)
|
128
|
-
# response.header (head of response as Hash)
|
129
|
-
# @example For REST it will be a RestClient::Response
|
130
|
-
def response
|
131
|
-
Soaspec.last_exchange = self
|
132
|
-
@response ||= make_request
|
133
|
-
@response.define_singleton_method(:exchange) { Soaspec.last_exchange } unless @response.respond_to?(:exchange)
|
134
|
-
@response
|
135
|
-
end
|
136
|
-
|
137
|
-
alias call response
|
138
|
-
|
139
|
-
# Request of API call. Either intended request or actual request
|
140
|
-
def request
|
141
|
-
exchange_handler.request(@response)
|
142
|
-
end
|
143
|
-
|
144
|
-
# Get status code from api class. This is http response for Web Api
|
145
|
-
# @return [Integer] Status code from api class
|
146
|
-
def status_code
|
147
|
-
exchange_handler.status_code_for(response)
|
148
|
-
end
|
149
|
-
|
150
|
-
# Dummy request used to make a request without verifying it and ignoring WSDL errors
|
151
|
-
# @return [Boolean] Always returns true. Unless of course an unexpected exception occurs
|
152
|
-
def dummy_request
|
153
|
-
make_request
|
154
|
-
true
|
155
|
-
rescue Savon::HTTPError
|
156
|
-
puts 'Resolver error'
|
157
|
-
# This seems to occur first time IP address asks for WSDL
|
158
|
-
true
|
159
|
-
end
|
160
|
-
|
161
|
-
# @return [Boolean] Whether an element exists at the path
|
162
|
-
def element?(path)
|
163
|
-
[path]
|
164
|
-
true
|
165
|
-
rescue NoElementAtPath
|
166
|
-
false
|
167
|
-
end
|
168
|
-
|
169
|
-
# Extract value from path api class
|
170
|
-
# @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
|
171
|
-
# @return [String] Value at path
|
172
|
-
def [](path)
|
173
|
-
exchange_handler.value_from_path(response, path.to_s)
|
174
|
-
end
|
175
|
-
|
176
|
-
# Set a parameter request in the request body.
|
177
|
-
# Can be used to build a request over several steps (e.g Cucumber)
|
178
|
-
# Will be used with FactoryBot
|
179
|
-
def []=(key, value)
|
180
|
-
@override_parameters[:body] ||= {}
|
181
|
-
@override_parameters[:body][key] = value
|
182
|
-
end
|
183
|
-
|
184
|
-
# Implement undefined setter with []= for FactoryBot to use without needing to define params to set
|
185
|
-
# @param [Object] method_name Name of method not defined
|
186
|
-
# @param [Object] args Arguments passed to method
|
187
|
-
# @param [Object] block
|
188
|
-
def method_missing(method_name, *args, &block)
|
189
|
-
set_value = args.first
|
190
|
-
if method_name[-1] == '=' # A setter method
|
191
|
-
getter_name = method_name[0..-2]
|
192
|
-
if set_value.class < Exchange # This would be prerequisite exchange
|
193
|
-
define_singleton_method(getter_name) { set_value }
|
194
|
-
self[getter_name] = set_value.id if set_value.respond_to?(:id)
|
195
|
-
else
|
196
|
-
self[getter_name] = set_value
|
197
|
-
end
|
198
|
-
else
|
199
|
-
super
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
# Used for setters that are not defined
|
204
|
-
def respond_to_missing?(method_name, *args)
|
205
|
-
method_name[-1] == '=' || super
|
206
|
-
end
|
207
|
-
|
208
|
-
# Makes request, caching the response and returning self
|
209
|
-
# Used by FactoryBot
|
210
|
-
# @return [Self]
|
211
|
-
def save!
|
212
|
-
@retry_for_success = @fail_factory ? false : true
|
213
|
-
call
|
214
|
-
self
|
215
|
-
end
|
216
|
-
|
217
|
-
# @return [Hash] Hash representing the response of the API
|
218
|
-
def to_hash
|
219
|
-
exchange_handler.to_hash(response)
|
220
|
-
end
|
221
|
-
|
222
|
-
# Wait until the passed block returns true
|
223
|
-
# @param [Hash] opts Options for this instance
|
224
|
-
# @option opts [Numeric] :timeout (5) Seconds to wait before timing out.
|
225
|
-
# @option opts [Numeric] :interval (0.2) Seconds to sleep between polls.
|
226
|
-
# @option opts [String] :message Exception mesage if timed out.
|
227
|
-
# @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Error::NoSuchElementError)
|
228
|
-
# @return [Self] Returns itself so operations can be done on the exchange after it's done waiting
|
229
|
-
def until(opts = {}, &script)
|
230
|
-
Soaspec::Wait.until(opts) do
|
231
|
-
@response = nil # Reset response so it can be made repeatedly
|
232
|
-
instance_eval(&script)
|
233
|
-
end
|
234
|
-
self
|
235
|
-
end
|
236
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# Convenience methods to set Exchange specific properties
|
2
|
-
# Will be used when creating a subclass of Exchange
|
3
|
-
module ExchangeProperties
|
4
|
-
# Set default exchange handler for this exchange
|
5
|
-
# This is helpful for when you need a new exchange handler created for each exchange
|
6
|
-
# @param [Class] handler_class Class of ExchangeHandler to set Exchange to use
|
7
|
-
# @param [String] name Name to call handler when it's instantiated (Defaults to class name)
|
8
|
-
# @param [Hash] params Hash of parameters to set for instance of ExchangeHandler
|
9
|
-
def default_handler(handler_class, name = handler_class.to_s, params = '')
|
10
|
-
define_method('default_handler_used') do
|
11
|
-
params_used = Hash[params.map do |k, param|
|
12
|
-
[k, param.is_a?(String) ? ERB.new(param).result(binding) : param]
|
13
|
-
end]
|
14
|
-
handler_class.new name, params_used
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Set retry_for_success to true, retrying response until a successful status code is returned
|
19
|
-
def expect_positive_status(retry_count: 3)
|
20
|
-
define_method('retry_count') do
|
21
|
-
retry_count
|
22
|
-
end
|
23
|
-
define_method('retry_for_success?') do
|
24
|
-
true
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|