soaspec 0.2.24 → 0.2.25

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.
Files changed (83) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +51 -33
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +588 -577
  8. data/Gemfile +6 -6
  9. data/LICENSE.txt +21 -21
  10. data/README.md +230 -230
  11. data/Rakefile +50 -42
  12. data/Todo.md +15 -15
  13. data/exe/soaspec +137 -123
  14. data/exe/xml_to_yaml_file +42 -42
  15. data/lib/soaspec.rb +103 -101
  16. data/lib/soaspec/core_ext/hash.rb +42 -35
  17. data/lib/soaspec/cucumber/generic_steps.rb +85 -85
  18. data/lib/soaspec/demo.rb +4 -4
  19. data/lib/soaspec/exchange/exchange.rb +117 -111
  20. data/lib/soaspec/exchange/exchange_extractor.rb +83 -83
  21. data/lib/soaspec/exchange/exchange_properties.rb +26 -26
  22. data/lib/soaspec/exchange/exchange_repeater.rb +19 -19
  23. data/lib/soaspec/exchange/request_builder.rb +68 -68
  24. data/lib/soaspec/exchange/variable_storer.rb +22 -22
  25. data/lib/soaspec/exchange_handlers/exchange_handler.rb +130 -126
  26. data/lib/soaspec/exchange_handlers/handler_accessors.rb +130 -130
  27. data/lib/soaspec/exchange_handlers/request/rest_request.rb +49 -0
  28. data/lib/soaspec/exchange_handlers/request/soap_request.rb +39 -0
  29. data/lib/soaspec/exchange_handlers/response_extractor.rb +82 -82
  30. data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +109 -109
  31. data/lib/soaspec/exchange_handlers/rest_handler.rb +287 -259
  32. data/lib/soaspec/exchange_handlers/rest_methods.rb +63 -44
  33. data/lib/soaspec/exchange_handlers/rest_parameters.rb +90 -86
  34. data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +40 -21
  35. data/lib/soaspec/exchange_handlers/soap_handler.rb +239 -235
  36. data/lib/soaspec/exe_helpers.rb +92 -92
  37. data/lib/soaspec/generate_server.rb +46 -37
  38. data/lib/soaspec/generator/.rspec.erb +5 -5
  39. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  40. data/lib/soaspec/generator/Gemfile.erb +8 -8
  41. data/lib/soaspec/generator/README.md.erb +29 -29
  42. data/lib/soaspec/generator/Rakefile.erb +19 -19
  43. data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
  44. data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
  45. data/lib/soaspec/generator/features/support/env.rb.erb +3 -0
  46. data/lib/soaspec/generator/generate_exchange.html.erb +47 -35
  47. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  48. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  49. data/lib/soaspec/generator/lib/new_rest_service.rb.erb +56 -51
  50. data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
  51. data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
  52. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  53. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  54. data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
  55. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  56. data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
  57. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  58. data/lib/soaspec/indifferent_hash.rb +7 -7
  59. data/lib/soaspec/interpreter.rb +39 -39
  60. data/lib/soaspec/matchers.rb +114 -114
  61. data/lib/soaspec/not_found_errors.rb +13 -13
  62. data/lib/soaspec/o_auth2.rb +128 -128
  63. data/lib/soaspec/soaspec_shared_examples.rb +24 -24
  64. data/lib/soaspec/spec_logger.rb +122 -121
  65. data/lib/soaspec/template_reader.rb +28 -28
  66. data/lib/soaspec/test_server/bank.wsdl +90 -90
  67. data/lib/soaspec/test_server/get_bank.rb +164 -164
  68. data/lib/soaspec/test_server/id_manager.rb +39 -39
  69. data/lib/soaspec/test_server/invoices.rb +27 -27
  70. data/lib/soaspec/test_server/namespace.xml +14 -14
  71. data/lib/soaspec/test_server/note.xml +5 -5
  72. data/lib/soaspec/test_server/puppy_service.rb +19 -19
  73. data/lib/soaspec/test_server/test_attribute.rb +12 -12
  74. data/lib/soaspec/test_server/test_namespace.rb +12 -12
  75. data/lib/soaspec/version.rb +4 -4
  76. data/lib/soaspec/virtual_server.rb +174 -174
  77. data/lib/soaspec/wait.rb +41 -41
  78. data/lib/soaspec/wsdl_generator.rb +215 -215
  79. data/soaspec.gemspec +56 -53
  80. data/test.wsdl +116 -116
  81. data/test.xml +10 -10
  82. data/test_wsdl.rb +41 -41
  83. metadata +38 -6
data/lib/soaspec/demo.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Load this file for demoing Soaspec (e.g in IRB). Has common settings applicable for demoing
2
-
3
- require_relative '../soaspec'
4
- Soaspec::SpecLogger.output_to_terminal = true
1
+ # Load this file for demoing Soaspec (e.g in IRB). Has common settings applicable for demoing
2
+
3
+ require_relative '../soaspec'
4
+ Soaspec::SpecLogger.output_to_terminal = true
@@ -1,111 +1,117 @@
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
- # Create new Exchange according to parameters set. A response will be made if called
47
- # explicitly with 'response' method or through other methods that use it like 'status_code'
48
- # @param [Symbol, String] name Name shown in RSpec run
49
- # @param [Hash] override_parameters Parameters to override for default params
50
- def initialize(name = self.class.to_s, override_parameters = {})
51
- self.test_name ||= name.to_s
52
- # As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
53
- @exchange_handler ||= default_handler_used || Soaspec.api_handler
54
- raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
55
-
56
- @fail_factory = nil
57
- @override_parameters = override_parameters
58
- @retry_for_success = false
59
- self.retry_count = 3
60
- @exchange_handler.elements.each { |element| methods_for_element(element) }
61
- end
62
-
63
- # Make request to handler with parameters defined
64
- # Will retry until success code reached if retry_for_success? is set
65
- # @return [Response] Response from Api handler
66
- def make_request
67
- Soaspec::SpecLogger.info 'Example ' + test_name
68
- request_params = @override_parameters
69
- (0..retry_count).each do |count|
70
- response = exchange_handler.make_request(request_params)
71
- return response unless retry_for_success?
72
- return response if (200..299).cover? exchange_handler.status_code_for(response)
73
-
74
- sleep 0.5 # Time before retrying
75
- break response if count == retry_count
76
- end
77
- end
78
-
79
- # Name describing this class when used with `RSpec.describe`
80
- # This will make the request and store the response
81
- # @return [String] Name given when initializing
82
- def to_s
83
- test_name
84
- end
85
-
86
- # @return [RestClient::Response,Savon::Response] Returns response object from Api.
87
- # Will make the request if not made and then cache it for later on
88
- # @example For SOAP it will be a Savon response
89
- # response.body (body of response as Hash)
90
- # response.header (head of response as Hash)
91
- # @example For REST it will be a RestClient::Response
92
- def response
93
- require 'forwardable'
94
- Soaspec.last_exchange = self
95
- @response ||= make_request
96
- @response.define_singleton_method(:exchange) { Soaspec.last_exchange } unless @response.respond_to?(:exchange)
97
- @response.extend Forwardable
98
- @response.delegate %i[value_from_path values_from_path] => :exchange
99
- @response
100
- end
101
-
102
- # @return [ResponseObject] Currently returning response object. This will change (in 0.3) to be itself to
103
- # allow easy method chaining
104
- def call
105
- if Soaspec.log_warnings
106
- warn 'This "call" method will be changed to return "Exchange" object in 0.3. ' \
107
- 'Use "response" method if you want the "response" object'
108
- end
109
- response
110
- end
111
- end
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
+ #
12
+ # It is tied to an ExchangeHandler that needs to be defined either globally before it's created or in 'default_handler_used'
13
+ class Exchange
14
+ extend Soaspec::ExchangeProperties
15
+ include Soaspec::ExchangeExtractor
16
+ include Soaspec::RequestBuilder
17
+ include Soaspec::ExchangeRepeater
18
+ include Soaspec::VariableStorer
19
+
20
+ # Instance of ExchangeHandler for which this exchange is made
21
+ attr_accessor :exchange_handler
22
+ # How many times to retry for a success
23
+ attr_accessor :retry_count
24
+ # Name used for displaying class
25
+ attr_accessor :test_name
26
+ # Expect Factory to fail upon trying to create
27
+ attr_writer :fail_factory
28
+ # Parameters to override for default params
29
+ attr_accessor :override_parameters
30
+
31
+ # Set retry for success variable to true so that request will be retried
32
+ # for retry_count until it's true
33
+ def retry_for_success
34
+ @retry_for_success = true
35
+ self
36
+ end
37
+
38
+ # @return [Bool] Whether to keep making request until success code reached
39
+ def retry_for_success?
40
+ @retry_for_success
41
+ end
42
+
43
+ # Override this in subclass to tie that subclass to an ExchangeHandler
44
+ # @return [Soaspec::ExchangeHandler] Soaspec::ExchangeHandler used by this exchange
45
+ def default_handler_used; end
46
+
47
+ # Create new Exchange according to parameters set. A response will be made if called
48
+ # explicitly with 'response' method or through other methods that use it like 'status_code'
49
+ # @param [Symbol, String] name Name shown in RSpec run
50
+ # @param [Hash] override_parameters Parameters to override for default params
51
+ def initialize(name = self.class.to_s, override_parameters = {})
52
+ self.test_name ||= name.to_s
53
+ # As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
54
+ @exchange_handler ||= default_handler_used || Soaspec.api_handler
55
+ raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
56
+
57
+ @fail_factory = nil
58
+ @override_parameters = override_parameters
59
+ @retry_for_success = false
60
+ self.retry_count = 3
61
+ @exchange_handler.elements.each { |element| methods_for_element(element) }
62
+ end
63
+
64
+ # @return [Hash] Hash representing what will be sent
65
+ def request_parameters
66
+ exchange_handler.request_parameters(@override_parameters)
67
+ end
68
+
69
+ # Make request to handler with parameters defined
70
+ # Will retry until success code reached if retry_for_success? is set
71
+ # @return [Response] Response from Api handler
72
+ def make_request
73
+ Soaspec::SpecLogger.info 'Example ' + test_name
74
+ request_params = @override_parameters
75
+ (0..retry_count).each do |count|
76
+ response = exchange_handler.make_request(request_params)
77
+ return response unless retry_for_success?
78
+ return response if (200..299).cover? exchange_handler.status_code_for(response)
79
+
80
+ sleep 0.5 # Time before retrying
81
+ break response if count == retry_count
82
+ end
83
+ end
84
+
85
+ # Name describing this class when used with `RSpec.describe`
86
+ # This will make the request and store the response
87
+ # @return [String] Name given when initializing
88
+ def to_s
89
+ test_name
90
+ end
91
+
92
+ # @return [RestClient::Response,Savon::Response] Returns response object from Api.
93
+ # Will make the request if not made and then cache it for later on
94
+ # @example For SOAP it will be a Savon response
95
+ # response.body (body of response as Hash)
96
+ # response.header (head of response as Hash)
97
+ # @example For REST it will be a RestClient::Response
98
+ def response
99
+ require 'forwardable'
100
+ Soaspec.last_exchange = self
101
+ @response ||= make_request
102
+ @response.define_singleton_method(:exchange) { Soaspec.last_exchange } unless @response.respond_to?(:exchange)
103
+ @response.extend Forwardable
104
+ @response.delegate %i[value_from_path values_from_path] => :exchange
105
+ @response
106
+ end
107
+
108
+ # @return [ResponseObject] Currently returning response object. This will change (in 0.3) to be itself to
109
+ # allow easy method chaining
110
+ def call
111
+ if Soaspec.log_warnings
112
+ warn 'This "call" method will be changed to return "Exchange" object in 0.3. ' \
113
+ 'Use "response" method if you want the "response" object'
114
+ end
115
+ response
116
+ end
117
+ end
@@ -1,83 +1,83 @@
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
- # Request of API call. Either intended request or actual request
6
- # @return [Object] Object representing request of API
7
- def request
8
- exchange_handler.request(@response)
9
- end
10
-
11
- # Get status code from api class. This is http response code for Web Api
12
- # @return [Integer] Status code from api class
13
- def status_code
14
- exchange_handler.status_code_for(response)
15
- end
16
-
17
- # Extract value from path api class
18
- # @example Extract unique value
19
- # @exchange['unique_value_name']
20
- # @example Extract value via JSON path
21
- # @exchange['$..path.to.element']
22
- # @example Extract value via XPath
23
- # @exchange['//path/to/element']
24
- # @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
25
- # @return [String] Value at path
26
- def [](path)
27
- exchange_handler.value_from_path(response, path.to_s)
28
- end
29
-
30
- alias_method :value_from_path, :[]
31
-
32
- # Using same path syntax as []. Returns true of false depending on whether an element is found
33
- # @return [Boolean] Whether an element exists at the path
34
- def element?(path)
35
- self[path]
36
- true
37
- rescue NoElementAtPath
38
- false
39
- end
40
-
41
- # @example Counting items in a JSON list
42
- # # Say there is JSON response {"notes":[{"title":"note1","note":"A note"},{"title":"note2"}]}
43
- # titles = @exchange.values_at_path('$..title')
44
- # expect(titles.count).to eq 2
45
- # expect(titles.first).to eq 'note1'
46
- # @param [String] path XPath, JSONPath to extract value
47
- # @param [String] attribute Attribute to obtain from XML element
48
- # @return [Array] List of values found at path
49
- def values_from_path(path, attribute: nil)
50
- exchange_handler.values_from_path(response, path, attribute: attribute)
51
- end
52
-
53
- # Return the response equivalent of the response. XML, JSON will be converted to a Hash
54
- # @example Counting items in a JSON list
55
- # # Say there is JSON response {"notes":[{"title":"note1","note":"A note"},{"title":"note2"}]}
56
- # hash = @exchange.to_hash
57
- # expect(hash['notes'].count).to eq 2
58
- # expect(hash['notes'].first['title']).to eq 'note1'
59
- # @return [Hash] Hash representing the response of the API
60
- def to_hash
61
- exchange_handler.to_hash(response)
62
- end
63
-
64
- private
65
-
66
- # Used to define methods on an exchange based on what's defined by the ExchangeHandler's methods
67
- # @param [String] element Element to define methods for
68
- def methods_for_element(element)
69
- element_name = element.to_s.split('__custom_path_').last
70
- define_singleton_method(element_name) do
71
- exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
72
- end
73
- define_singleton_method("#{element_name}?") do
74
- begin
75
- __send__ element_name
76
- true
77
- rescue NoElementAtPath
78
- false
79
- end
80
- end
81
- end
82
- end
83
- end
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
+ # Request of API call. Either intended request or actual request
6
+ # @return [Object] Object representing request of API
7
+ def request
8
+ exchange_handler.request(@response)
9
+ end
10
+
11
+ # Get status code from api class. This is http response code for Web Api
12
+ # @return [Integer] Status code from api class
13
+ def status_code
14
+ exchange_handler.status_code_for(response)
15
+ end
16
+
17
+ # Extract value from path api class
18
+ # @example Extract unique value
19
+ # @exchange['unique_value_name']
20
+ # @example Extract value via JSON path
21
+ # @exchange['$..path.to.element']
22
+ # @example Extract value via XPath
23
+ # @exchange['//path/to/element']
24
+ # @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
25
+ # @return [String] Value at path
26
+ def [](path)
27
+ exchange_handler.value_from_path(response, path.to_s)
28
+ end
29
+
30
+ alias_method :value_from_path, :[]
31
+
32
+ # Using same path syntax as []. Returns true of false depending on whether an element is found
33
+ # @return [Boolean] Whether an element exists at the path
34
+ def element?(path)
35
+ self[path]
36
+ true
37
+ rescue NoElementAtPath
38
+ false
39
+ end
40
+
41
+ # @example Counting items in a JSON list
42
+ # # Say there is JSON response {"notes":[{"title":"note1","note":"A note"},{"title":"note2"}]}
43
+ # titles = @exchange.values_at_path('$..title')
44
+ # expect(titles.count).to eq 2
45
+ # expect(titles.first).to eq 'note1'
46
+ # @param [String] path XPath, JSONPath to extract value
47
+ # @param [String] attribute Attribute to obtain from XML element
48
+ # @return [Array] List of values found at path
49
+ def values_from_path(path, attribute: nil)
50
+ exchange_handler.values_from_path(response, path, attribute: attribute)
51
+ end
52
+
53
+ # Return the response equivalent of the response. XML, JSON will be converted to a Hash
54
+ # @example Counting items in a JSON list
55
+ # # Say there is JSON response {"notes":[{"title":"note1","note":"A note"},{"title":"note2"}]}
56
+ # hash = @exchange.to_hash
57
+ # expect(hash['notes'].count).to eq 2
58
+ # expect(hash['notes'].first['title']).to eq 'note1'
59
+ # @return [Hash] Hash representing the response of the API
60
+ def to_hash
61
+ exchange_handler.to_hash(response)
62
+ end
63
+
64
+ private
65
+
66
+ # Used to define methods on an exchange based on what's defined by the ExchangeHandler's methods
67
+ # @param [String] element Element to define methods for
68
+ def methods_for_element(element)
69
+ element_name = element.to_s.split('__custom_path_').last
70
+ define_singleton_method(element_name) do
71
+ exchange_handler.__send__(element, response) # Forward the call onto handler to retrieve the element for the response
72
+ end
73
+ define_singleton_method("#{element_name}?") do
74
+ begin
75
+ __send__ element_name
76
+ true
77
+ rescue NoElementAtPath
78
+ false
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,26 +1,26 @@
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
- # @param [Integer] retry_count Times to retry to get a positive response
21
- def expect_positive_status(retry_count: 3)
22
- define_method('retry_count') { retry_count }
23
- define_method('retry_for_success?') { true }
24
- end
25
- end
26
- end
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
+ # @param [Integer] retry_count Times to retry to get a positive response
21
+ def expect_positive_status(retry_count: 3)
22
+ define_method('retry_count') { retry_count }
23
+ define_method('retry_for_success?') { true }
24
+ end
25
+ end
26
+ end