soaspec 0.1.12 → 0.1.13

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