soaspec 0.2.24 → 0.2.25

Sign up to get free protection for your applications and to get access to all the features.
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