soaspec 0.1.12 → 0.1.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c021efb99c24b3ab3c9e20d17d9a6162dbc2000
4
- data.tar.gz: 8a565f97656d00caaa5f3d55f17d76ef3d2e0966
3
+ metadata.gz: 85a80e81b02c106032a9d6843aec406708137ea7
4
+ data.tar.gz: 1f50e802564fdc610ecf72ca8bbdb33a63ddff95
5
5
  SHA512:
6
- metadata.gz: 29afe2d8539a57f203330bc5a869648dbfa018c27aba144af9d5343a592c74591c0d07cec5c22439d5286200a01d27ecd4fbee6b646aa8145a434950f8b7ff5b
7
- data.tar.gz: eec926fd442193365280f711ed49d705dfa6b29de63cb18714af7101b5d9c1b469d73586d5c775dea9135eb02f077b7224d7a9dbedf5aedade90fb2549bdcc3f
6
+ metadata.gz: 0e72ef672e17b4fbf87078fd950c173fd09610b480c8b40b26cdbe00a0e8e878fd87a81d5a21a2bdd416a2edfa5ee336d0b3f2c3ba218584d1ab90a682666ba4
7
+ data.tar.gz: 534d5ceb6f6888a29ce223f7f00bae1722f9f75ef8ca63cf1cd011356f279a61a953c31fc3956b97b65256cc09b61ddc4d652a13cb010b18fbac7660f246c693
data/ChangeLog CHANGED
@@ -1,3 +1,9 @@
1
+ Version 0.1.13
2
+ * Enhancements
3
+ * Cleaned up comments (mainly OAuth2 related)
4
+ * Cleaned up REST handler code, adding more comments on usage
5
+ * Added 'soaspec/cucumber/generic_steps' to simplify reusing code and also demonstrate how gem can be used
6
+
1
7
  Version 0.1.12
2
8
  * Enhancements
3
9
  * Add 'refresh_token' attribute to Soaspec::OAuth2 class so that token can be retrieved once and then stored
@@ -0,0 +1,49 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ Given 'I am performing a {word} on the {string} API' do |operation, api_name|
4
+ @exchange = api_name.camelize.constantize.send operation
5
+ end
6
+
7
+ Given 'I set the {word} to {string}' do |key, value|
8
+ @exchange[key] = value
9
+ end
10
+
11
+ Given 'I use the path {word}' do |suburl|
12
+ @exchange.suburl = suburl
13
+ end
14
+
15
+ Given 'I filter {string} by {string}' do |filter_key, filter_value|
16
+ transformed_key = filter_key.to_sym
17
+ if @exchange.override_parameters[:q]
18
+ @exchange.override_parameters[:q][transformed_key] = filter_value
19
+ else
20
+ @exchange.override_parameters[:q] = { transformed_key => filter_value }
21
+ end
22
+ end
23
+
24
+ # This is getting quite technical
25
+ Given 'I set header {string} to {string}' do |header_name, header_value|
26
+ if @exchange.override_parameters[:params]
27
+ @exchange.override_parameters[:params][header_name] = header_value
28
+ else
29
+ @exchange.override_parameters[:params] = { header_name => header_value }
30
+ end
31
+ end
32
+
33
+ When 'I make the request' do
34
+ @exchange.call
35
+ end
36
+
37
+ Then 'it should have the {word} {string}' do |key, expected_value|
38
+ expect(@exchange[key]).to eq expected_value
39
+ end
40
+
41
+ Then 'it should have the {string} {string}' do |key_string, expected_value|
42
+ key = key_string.tr(' ', '_')
43
+ actual_value = @exchange.respond_to?(key) ? @exchange.send(key) : @exchange[key]
44
+ expect(actual_value.to_s).to eq expected_value
45
+ end
46
+
47
+ Then 'it should be successful' do
48
+ expect(200..299).to cover @exchange.status_code
49
+ end
@@ -40,7 +40,8 @@ class Exchange
40
40
  attr_accessor :test_name
41
41
  # Expect Factory to fail upon trying to create
42
42
  attr_writer :fail_factory
43
-
43
+ # Parameters to override for default params
44
+ attr_accessor :override_parameters
44
45
 
45
46
  def values_from_path(path, attribute: nil)
46
47
  exchange_handler.values_from_path(response, path, attribute: attribute)
@@ -88,6 +88,13 @@ module Soaspec
88
88
  end
89
89
  end
90
90
 
91
+ # Set instance variable for each key in hash remove it from Hash
92
+ # @param [Hash] hash with items to remove from
93
+ # @param [Array] keys List of keys to remove from hash, setting each one
94
+ def set_remove_keys(hash, keys)
95
+ keys.each { |key| set_remove_key(hash, key) }
96
+ end
97
+
91
98
  # Set instance variable and remove it from Hash
92
99
  def set_remove_key(hash, key)
93
100
  return unless hash.key? key
@@ -1,3 +1,5 @@
1
+ require_relative 'rest_accessors_defaults'
2
+
1
3
  module Soaspec
2
4
  # Accessors specific to REST handler
3
5
  module RestAccessors
@@ -11,25 +13,20 @@ module Soaspec
11
13
  end
12
14
 
13
15
  # Will create access_token method based on passed parameters
14
- # @param [Hash] params Params client_id: nil, client_secret: nil, token_url: nil, username: nil, password: nil, security_token: nil
16
+ # @param [Hash] params OAuth 2 parameters
17
+ # @param_value [token_url] URL to retrieve OAuth token from. @Note this can be set globally instead of here
18
+ # @param_value [client_id] Client ID
19
+ # @param_value [client_secret] Client Secret
20
+ # @param_value [username] Username used in password grant
21
+ # @param_value [password] Password used in password grant
22
+ # @param_value [security_token] Security Token used in password grant
15
23
  def oauth2(params)
16
- # Object to handle oauth2
17
- define_method('oauth_obj') do
18
- OAuth2.new(params, api_username)
19
- end
20
-
21
- # Method to send request to get oauth token based on parameters
22
- define_method('oauth_response') do
23
- oauth_obj.response
24
- end
25
-
26
- define_method('access_token') do
27
- oauth_obj.access_token
28
- end
29
-
30
- define_method('instance_url') do
31
- oauth_response['instance_url']
32
- end
24
+ # @!method oauth_obj Object to handle oauth2
25
+ define_method('oauth_obj') { OAuth2.new(params, api_username) }
26
+ # @!method access_token Retrieve OAuth2 access token
27
+ define_method('access_token') { oauth_obj.access_token }
28
+ # @!method instance_url Retrieve instance url from OAuth request
29
+ define_method('instance_url') { oauth_obj.response['instance_url'] }
33
30
  end
34
31
 
35
32
  # Pass path to YAML file containing OAuth2 parameters
@@ -0,0 +1,21 @@
1
+ module Soaspec
2
+ # Defaults for Soaspec RestAccessors method
3
+ module RestAccessorsDefaults
4
+ # Set through following method. Base URL in REST requests.
5
+ def base_url_value
6
+ nil
7
+ end
8
+
9
+ # Headers used in RestClient
10
+ def rest_client_headers
11
+ {}
12
+ end
13
+
14
+ # Whether to convert each key in the request to PascalCase
15
+ # It will also auto convert simple XPath, JSONPath where '//' or '..' not specified
16
+ # @return Whether to convert to PascalCase
17
+ def pascal_keys?
18
+ false
19
+ end
20
+ end
21
+ end
@@ -14,18 +14,60 @@ module Soaspec
14
14
  # Wraps around Savon client defining default values dependent on the soap request
15
15
  class RestHandler < ExchangeHandler
16
16
  extend Soaspec::RestAccessors
17
+ include Soaspec::RestAccessorsDefaults
17
18
 
18
19
  # User used in making API calls
19
20
  attr_accessor :api_username
20
21
 
21
- # Set through following method. Base URL in REST requests.
22
- def base_url_value
23
- nil
22
+ # Setup object to handle communicating with a particular SOAP WSDL
23
+ # @param [Hash] options Options defining REST request. base_url, default_hash
24
+ def initialize(name = self.class.to_s, options = {})
25
+ raise "Base URL not set! Please set in class with 'base_url' method" unless base_url_value
26
+ @default_hash = {}
27
+ if name.is_a?(Hash) && options == {} # If name is not set, use first parameter as the options hash
28
+ options = name
29
+ name = self.class.to_s
30
+ end
31
+ super
32
+ set_remove_keys(options, %i[api_username default_hash template_name])
33
+ @init_options = options
24
34
  end
25
35
 
26
- # Headers used in RestClient
27
- def rest_client_headers
28
- {}
36
+ # Used in together with Exchange request that passes such override parameters
37
+ # @param [Hash] override_parameters Params to characterize REST request
38
+ # @option override_parameters [Hash] :params Extra parameters (E.g. headers)
39
+ # @option override_parameters [String] suburl URL appended to base_url of class
40
+ # @option override_parameters [Hash] :q Query for REST
41
+ # @option override_parameters [Symbol] :method REST method (:get, :post, :patch, etc)
42
+ # Following are for the body of the request
43
+ # @option override_parameters [Hash] :body Hash to be converted to JSON in request body
44
+ # @option override_parameters [String] :payload String to be passed directly in request body
45
+ # @option override_parameters [String] :template_name Path to file to be read via ERB and passed in request body
46
+ def make_request(override_parameters)
47
+ @merged_options ||= init_merge_options
48
+ test_values = override_parameters
49
+ test_values[:params] ||= {}
50
+ test_values[:method] ||= :post
51
+ test_values[:suburl] = test_values[:suburl].to_s if test_values[:suburl]
52
+ test_values[:params][:params] = test_values[:q] if test_values[:q] # Use q for query parameters. Nested :params is ugly and long
53
+ # In order for ERB to be calculated at correct time, the first time request is made, the resource should be created
54
+ @resource ||= RestClient::Resource.new(ERB.new(base_url_value).result(binding), @merged_options)
55
+
56
+ @resource_used = test_values[:suburl] ? @resource[test_values[:suburl]] : @resource
57
+
58
+ begin
59
+ response = case test_values[:method]
60
+ when :post, :patch, :put
61
+ Soaspec::SpecLogger.info("request body: #{post_data(test_values)}")
62
+ @resource_used.send(test_values[:method].to_s, post_data(test_values), test_values[:params])
63
+ else # :get, :delete
64
+ @resource_used.send(test_values[:method].to_s, test_values[:params])
65
+ end
66
+ rescue RestClient::ExceptionWithResponse => e
67
+ response = e.response
68
+ end
69
+ Soaspec::SpecLogger.info(["response_headers: #{response.headers}", "response_body: #{response}"])
70
+ response
29
71
  end
30
72
 
31
73
  # Add values to here when extending this class to have default REST options.
@@ -43,35 +85,12 @@ module Soaspec
43
85
  Hash[rest_client_headers.map { |k, header| [k, ERB.new(header).result(binding)] }]
44
86
  end
45
87
 
46
- # Setup object to handle communicating with a particular SOAP WSDL
47
- # @param [Hash] options Options defining SOAP request. WSDL, authentication
48
- def initialize(name = self.class.to_s, options = {})
49
- raise "Base URL not set! Please set in class with 'base_url' method" unless base_url_value
50
- @default_hash = {}
51
- if name.is_a?(Hash) && options == {} # If name is not set
52
- options = name
53
- name = self.class.to_s
54
- end
55
- super
56
- set_remove_key(options, :api_username)
57
- set_remove_key(options, :default_hash)
58
- set_remove_key(options, :template_name)
59
- @init_options = options
60
- end
61
-
62
88
  # Convert snakecase to PascalCase
63
89
  def convert_to_pascal_case(key)
64
90
  return key if /[[:upper:]]/ =~ key[0] # If first character already capital, don't do conversion
65
91
  key.split('_').map(&:capitalize).join
66
92
  end
67
93
 
68
- # Whether to convert each key in the request to PascalCase
69
- # It will also auto convert simple XPath, JSONPath where '//' or '..' not specified
70
- # @return Whether to convert to PascalCase
71
- def pascal_keys?
72
- false
73
- end
74
-
75
94
  # Initialize value of merged options
76
95
  # @return [Hash] Hash of merged options
77
96
  def init_merge_options
@@ -84,40 +103,6 @@ module Soaspec
84
103
  options.merge(@init_options)
85
104
  end
86
105
 
87
- # Used in together with Exchange request that passes such override parameters
88
- # @param [Hash] override_parameters Params to characterize REST request
89
- # @param_value [params] Extra parameters (E.g. headers)
90
- # @param_value [suburl] URL appended to base_url of class
91
- # @param_value [q] Query for REST
92
- # @param_value [method] REST method (:get, :post, etc)
93
- def make_request(override_parameters)
94
- @merged_options ||= init_merge_options
95
- test_values = override_parameters
96
- test_values[:params] ||= {}
97
- test_values[:method] ||= :post
98
- test_values[:suburl] = test_values[:suburl].to_s if test_values[:suburl]
99
- test_values[:params][:params] = test_values[:q] if test_values[:q] # Use q for query parameters. Nested :params is ugly and long
100
- # In order for ERB to be calculated at correct time, the first time request is made, the resource should be created
101
- @resource ||= RestClient::Resource.new(ERB.new(base_url_value).result(binding), @merged_options)
102
-
103
- @resource_used = test_values[:suburl] ? @resource[test_values[:suburl]] : @resource
104
-
105
- begin
106
- response = case test_values[:method]
107
- when :post, :patch, :put
108
- Soaspec::SpecLogger.info("request body: #{post_data(test_values)}")
109
- @resource_used.send(test_values[:method].to_s, post_data(test_values), test_values[:params])
110
- else # :get, :delete
111
- @resource_used.send(test_values[:method].to_s, test_values[:params])
112
- end
113
- rescue RestClient::ExceptionWithResponse => e
114
- response = e.response
115
- end
116
- Soaspec::SpecLogger.info('response_headers: ' + response.headers.to_s)
117
- Soaspec::SpecLogger.info('response_body: ' + response.to_s)
118
- response
119
- end
120
-
121
106
  # @param [Hash] format Format of expected result.
122
107
  # @return [Object] Generic body to be displayed in error messages
123
108
  def response_body(response, format: :hash)
@@ -134,25 +119,6 @@ module Soaspec
134
119
  status_code_for(response) != 404
135
120
  end
136
121
 
137
- # Convert XML or JSON response into a Hash
138
- # @param [String] response Response as a String (either in XML or JSON)
139
- # @return [Hash]
140
- def extract_hash(response)
141
- raise ArgumentError("Empty Body. Can't assert on it") if response.body.empty?
142
- case Interpreter.response_type_for response
143
- when :json
144
- converted = JSON.parse(response.body)
145
- return converted.transform_keys_to_symbols if converted.is_a? Hash
146
- return converted.map!(&:transform_keys_to_symbols) if converted.is_a? Array
147
- raise 'Incorrect Type prodcued ' + converted.class
148
- when :xml
149
- parser = Nori.new(convert_tags_to: lambda { |tag| tag.snakecase.to_sym })
150
- parser.parse(response.body)
151
- else
152
- raise "Neither XML nor JSON detected. It is #{type}. Don't know how to parse It is #{response.body}"
153
- end
154
- end
155
-
156
122
  # @return [Boolean] Whether response contains expected value
157
123
  def include_value?(response, expected)
158
124
  extract_hash(response).include_value? expected
@@ -168,25 +134,6 @@ module Soaspec
168
134
  response.code
169
135
  end
170
136
 
171
- # Override this to specify elements that must be present in the response
172
- # Will be used in 'success_scenarios' shared examples
173
- # @return [Array] Array of symbols specifying element names
174
- def mandatory_elements
175
- []
176
- end
177
-
178
- # Override this to specify xpath results that must be present in the response
179
- # Will be used in 'success_scenarios' shared examples
180
- # @return [Hash] Hash of 'xpath' => 'expected value' pairs
181
- def mandatory_xpath_values
182
- {}
183
- end
184
-
185
- # Attributes set at the root XML element of SOAP request
186
- def root_attributes
187
- nil
188
- end
189
-
190
137
  # Returns the value at the provided xpath
191
138
  # @param [RestClient::Response] response
192
139
  # @param [String] xpath
@@ -259,6 +206,26 @@ module Soaspec
259
206
  end
260
207
  end
261
208
 
209
+ # TODO: This and 'to_hash' method should be merged
210
+ # Convert XML or JSON response into a Hash
211
+ # @param [String] response Response as a String (either in XML or JSON)
212
+ # @return [Hash]
213
+ def extract_hash(response)
214
+ raise ArgumentError("Empty Body. Can't assert on it") if response.body.empty?
215
+ case Interpreter.response_type_for response
216
+ when :json
217
+ converted = JSON.parse(response.body)
218
+ return converted.transform_keys_to_symbols if converted.is_a? Hash
219
+ return converted.map!(&:transform_keys_to_symbols) if converted.is_a? Array
220
+ raise 'Incorrect Type produced ' + converted.class
221
+ when :xml
222
+ parser = Nori.new(convert_tags_to: lambda { |tag| tag.snakecase.to_sym })
223
+ parser.parse(response.body)
224
+ else
225
+ raise "Neither XML nor JSON detected. It is #{type}. Don't know how to parse It is #{response.body}"
226
+ end
227
+ end
228
+
262
229
  # @return [Hash] Hash representing response body
263
230
  def to_hash(response)
264
231
  case Interpreter.response_type_for(response)
@@ -272,7 +239,7 @@ module Soaspec
272
239
  end
273
240
  end
274
241
 
275
- # Request of API call. Either intended request or actual request
242
+ # @response [RestClient::Request] Request of API call. Either intended request or actual request
276
243
  def request(response)
277
244
  return 'Request not yet sent' if response.nil?
278
245
  response.request
@@ -280,7 +247,7 @@ module Soaspec
280
247
 
281
248
  private
282
249
 
283
- # Work out data to send based upon payload, template_name
250
+ # Work out data to send based upon payload, template_name, or body
284
251
  # @return [String] Payload to send in REST request
285
252
  def post_data(test_values)
286
253
  data = if test_values[:body]
@@ -325,6 +292,5 @@ module Soaspec
325
292
  end
326
293
  end
327
294
  end
328
-
329
295
  end
330
- end
296
+ end
@@ -25,6 +25,12 @@ module Soaspec
25
25
  attr_accessor :retry_count
26
26
 
27
27
  # @param [Hash] params_sent Parameters to make OAuth request
28
+ # @param_value [token_url] URL to retrieve OAuth token from. @Note this can be set globally instead of here
29
+ # @param_value [client_id] Client ID
30
+ # @param_value [client_secret] Client Secret
31
+ # @param_value [username] Username used in password grant
32
+ # @param_value [password] Password used in password grant
33
+ # @param_value [security_token] Security Token used in password grant
28
34
  # @param [String] api_username Username to use which can be set by Soaspec::ExchangeHandler
29
35
  def initialize(params_sent, api_username = nil)
30
36
  params = params_sent.transform_keys_to_symbols
@@ -1,3 +1,3 @@
1
1
  module Soaspec
2
- VERSION = '0.1.12'.freeze
2
+ VERSION = '0.1.13'.freeze
3
3
  end
data/soaspec.gemspec CHANGED
@@ -30,6 +30,7 @@ the same configuration "
30
30
  spec.add_development_dependency 'require_all', '1.5.0'
31
31
  spec.add_development_dependency 'rspec', '~> 3.0'
32
32
  spec.add_development_dependency 'simplecov'
33
+ spec.add_dependency 'activesupport'
33
34
  spec.add_dependency 'faker'
34
35
  spec.add_dependency 'hashie'
35
36
  spec.add_dependency 'jsonpath'
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.1.12
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - SamuelGarrattIQA
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-25 00:00:00.000000000 Z
11
+ date: 2018-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: activesupport
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: faker
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -329,10 +343,12 @@ files:
329
343
  - exe/xml_to_yaml_file
330
344
  - lib/soaspec.rb
331
345
  - lib/soaspec/core_ext/hash.rb
346
+ - lib/soaspec/cucumber/generic_steps.rb
332
347
  - lib/soaspec/exchange.rb
333
348
  - lib/soaspec/exchange_handlers/exchange_handler.rb
334
349
  - lib/soaspec/exchange_handlers/handler_accessors.rb
335
350
  - lib/soaspec/exchange_handlers/rest_accessors.rb
351
+ - lib/soaspec/exchange_handlers/rest_accessors_defaults.rb
336
352
  - lib/soaspec/exchange_handlers/rest_handler.rb
337
353
  - lib/soaspec/exchange_handlers/rest_methods.rb
338
354
  - lib/soaspec/exchange_handlers/soap_handler.rb