soaspec 0.1.6 → 0.1.7

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 (60) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +48 -48
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +408 -404
  8. data/Gemfile +6 -6
  9. data/LICENSE.txt +21 -21
  10. data/README.md +113 -113
  11. data/Rakefile +24 -24
  12. data/Todo.md +6 -6
  13. data/exe/soaspec +109 -109
  14. data/exe/soaspec-virtual-server +156 -156
  15. data/exe/xml_to_yaml_file +60 -60
  16. data/lib/soaspec.rb +107 -103
  17. data/lib/soaspec/core_ext/hash.rb +83 -83
  18. data/lib/soaspec/exchange.rb +235 -235
  19. data/lib/soaspec/exchange_handlers/exchange_handler.rb +103 -103
  20. data/lib/soaspec/exchange_handlers/handler_accessors.rb +106 -106
  21. data/lib/soaspec/exchange_handlers/rest_accessors.rb +54 -92
  22. data/lib/soaspec/exchange_handlers/rest_handler.rb +318 -314
  23. data/lib/soaspec/exchange_handlers/rest_methods.rb +44 -44
  24. data/lib/soaspec/exchange_handlers/soap_handler.rb +236 -236
  25. data/lib/soaspec/exe_helpers.rb +60 -60
  26. data/lib/soaspec/generator/.rspec.erb +5 -5
  27. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  28. data/lib/soaspec/generator/Gemfile.erb +8 -8
  29. data/lib/soaspec/generator/README.md.erb +29 -29
  30. data/lib/soaspec/generator/Rakefile.erb +19 -19
  31. data/lib/soaspec/generator/config/data/default.yml.erb +1 -1
  32. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  33. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  34. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  35. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  36. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  37. data/lib/soaspec/generator/spec/spec_helper.rb.erb +20 -20
  38. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  39. data/lib/soaspec/interpreter.rb +40 -40
  40. data/lib/soaspec/matchers.rb +65 -65
  41. data/lib/soaspec/not_found_errors.rb +13 -13
  42. data/lib/soaspec/o_auth2.rb +65 -0
  43. data/lib/soaspec/soaspec_shared_examples.rb +24 -24
  44. data/lib/soaspec/spec_logger.rb +34 -27
  45. data/lib/soaspec/test_server/bank.wsdl +90 -90
  46. data/lib/soaspec/test_server/get_bank.rb +160 -160
  47. data/lib/soaspec/test_server/id_manager.rb +31 -31
  48. data/lib/soaspec/test_server/invoices.rb +27 -27
  49. data/lib/soaspec/test_server/namespace.xml +14 -14
  50. data/lib/soaspec/test_server/note.xml +5 -5
  51. data/lib/soaspec/test_server/puppy_service.rb +20 -20
  52. data/lib/soaspec/test_server/test_attribute.rb +13 -13
  53. data/lib/soaspec/test_server/test_namespace.rb +12 -12
  54. data/lib/soaspec/version.rb +2 -2
  55. data/lib/soaspec/wsdl_generator.rb +144 -144
  56. data/soaspec.gemspec +46 -46
  57. data/test.wsdl +116 -116
  58. data/test.xml +10 -10
  59. data/test_wsdl.rb +43 -43
  60. metadata +4 -3
@@ -1,20 +1,20 @@
1
-
2
- require 'soaspec'
3
- require 'require_all'
4
- require_all 'lib'
5
- require 'data_magic'
6
-
7
- include DataMagic # Used as example of loading data smartly. Use 'data_for' method to load yml data
8
-
9
- RSpec.configure do |config|
10
- # This will make backtrace much shorter by removing many lines from rspec failure message
11
- config.backtrace_exclusion_patterns = [
12
- /rspec/
13
- ]
14
- <% if @virtual %>
15
- # Close test server after all RSpec tests have run
16
- config.after(:suite) do
17
- Process.kill(:QUIT, ENV['test_server_pid'].to_i) if ENV['test_server_pid']
18
- end
19
- <% end %>
20
- end
1
+
2
+ require 'soaspec'
3
+ require 'require_all'
4
+ require_all 'lib'
5
+ require 'data_magic'
6
+
7
+ include DataMagic # Used as example of loading data smartly. Use 'data_for' method to load yml data
8
+
9
+ RSpec.configure do |config|
10
+ # This will make backtrace much shorter by removing many lines from rspec failure message
11
+ config.backtrace_exclusion_patterns = [
12
+ /rspec/
13
+ ]
14
+ <% if @virtual %>
15
+ # Close test server after all RSpec tests have run
16
+ config.after(:suite) do
17
+ Process.kill(:QUIT, ENV['test_server_pid'].to_i) if ENV['test_server_pid']
18
+ end
19
+ <% end %>
20
+ end
@@ -1,7 +1,7 @@
1
- <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
2
- <env:Body>
3
- <tns:getBank>
4
- <tns:blz><%= test_values[:blz] || '70070010' %></tns:blz>
5
- </tns:getBank>
6
- </env:Body>
1
+ <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
2
+ <env:Body>
3
+ <tns:getBank>
4
+ <tns:blz><%= test_values[:blz] || '70070010' %></tns:blz>
5
+ </tns:getBank>
6
+ </env:Body>
7
7
  </env:Envelope>
@@ -1,41 +1,41 @@
1
-
2
- # Help interpret the general type of a particular object
3
- class Interpreter
4
-
5
- class << self
6
- # @param [Object] response API response
7
- # @return [Symbol] Type of provided response
8
- def response_type_for(response)
9
- @response = response
10
- if @response.is_a? String
11
- if xml?
12
- :xml
13
- elsif json?
14
- :json
15
- else
16
- :unknown
17
- end
18
- elsif response.is_a? Hash
19
- :hash
20
- elsif response.is_a? Nokogiri::XML::NodeSet
21
- :xml
22
- else
23
- :unknown
24
- end
25
- end
26
-
27
- # @return [Boolean] Whether valid XML
28
- def xml?
29
- Nokogiri::XML(@response) { |config| config.options = Nokogiri::XML::ParseOptions::STRICT }
30
- rescue Nokogiri::XML::SyntaxError
31
- false
32
- end
33
-
34
- # @return [Boolean] Whether valid JSON
35
- def json?
36
- JSON.parse(@response)
37
- rescue JSON::ParserError
38
- false
39
- end
40
- end
1
+
2
+ # Help interpret the general type of a particular object
3
+ class Interpreter
4
+
5
+ class << self
6
+ # @param [Object] response API response
7
+ # @return [Symbol] Type of provided response
8
+ def response_type_for(response)
9
+ @response = response
10
+ if @response.is_a? String
11
+ if xml?
12
+ :xml
13
+ elsif json?
14
+ :json
15
+ else
16
+ :unknown
17
+ end
18
+ elsif response.is_a? Hash
19
+ :hash
20
+ elsif response.is_a? Nokogiri::XML::NodeSet
21
+ :xml
22
+ else
23
+ :unknown
24
+ end
25
+ end
26
+
27
+ # @return [Boolean] Whether valid XML
28
+ def xml?
29
+ Nokogiri::XML(@response) { |config| config.options = Nokogiri::XML::ParseOptions::STRICT }
30
+ rescue Nokogiri::XML::SyntaxError
31
+ false
32
+ end
33
+
34
+ # @return [Boolean] Whether valid JSON
35
+ def json?
36
+ JSON.parse(@response)
37
+ rescue JSON::ParserError
38
+ false
39
+ end
40
+ end
41
41
  end
@@ -1,66 +1,66 @@
1
-
2
- require_relative 'core_ext/hash'
3
- require_relative 'not_found_errors'
4
-
5
- # Whether response has any element with the provided value
6
- RSpec::Matchers.define :contain_value do |expected|
7
- match do |actual|
8
- expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true
9
- end
10
-
11
- failure_message do |actual|
12
- "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}"
13
- end
14
- end
15
-
16
- # Whether substring exists in body of response (more general than above)
17
- RSpec::Matchers.define :include_in_body do |expected|
18
- match do |actual|
19
- expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true
20
- end
21
-
22
- failure_message do |actual|
23
- "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}"
24
- end
25
- end
26
-
27
- # Whether an element exists at expected xpath
28
- RSpec::Matchers.define :have_element_at_path do |xpath|
29
- match do |exchange|
30
- expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value
31
- end
32
-
33
- # TODO: Would be better to print failure message
34
- failure_message do |actual|
35
- "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would have element at path '#{xpath}'"
36
- end
37
- end
38
-
39
- RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path
40
- RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path
41
-
42
- # Whether an element at xpath (defined by key) has value (defined by value).
43
- # @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found')
44
- RSpec::Matchers.define :have_xpath_value do |expected_hash|
45
- match do |exchange|
46
- expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring
47
- expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first
48
- end
49
-
50
- failure_message do |actual|
51
- "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'"
52
- end
53
-
54
- end
55
-
56
- RSpec::Matchers.define :be_found do
57
-
58
- match do |exchange|
59
- expect(exchange.exchange_handler.found?(exchange.response)).to be true
60
- end
61
-
62
- failure_message do |exchange|
63
- "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}"
64
- end
65
-
1
+
2
+ require_relative 'core_ext/hash'
3
+ require_relative 'not_found_errors'
4
+
5
+ # Whether response has any element with the provided value
6
+ RSpec::Matchers.define :contain_value do |expected|
7
+ match do |actual|
8
+ expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true
9
+ end
10
+
11
+ failure_message do |actual|
12
+ "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}"
13
+ end
14
+ end
15
+
16
+ # Whether substring exists in body of response (more general than above)
17
+ RSpec::Matchers.define :include_in_body do |expected|
18
+ match do |actual|
19
+ expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true
20
+ end
21
+
22
+ failure_message do |actual|
23
+ "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}"
24
+ end
25
+ end
26
+
27
+ # Whether an element exists at expected xpath
28
+ RSpec::Matchers.define :have_element_at_path do |xpath|
29
+ match do |exchange|
30
+ expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value
31
+ end
32
+
33
+ # TODO: Would be better to print failure message
34
+ failure_message do |actual|
35
+ "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would have element at path '#{xpath}'"
36
+ end
37
+ end
38
+
39
+ RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path
40
+ RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path
41
+
42
+ # Whether an element at xpath (defined by key) has value (defined by value).
43
+ # @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found')
44
+ RSpec::Matchers.define :have_xpath_value do |expected_hash|
45
+ match do |exchange|
46
+ expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring
47
+ expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first
48
+ end
49
+
50
+ failure_message do |actual|
51
+ "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'"
52
+ end
53
+
54
+ end
55
+
56
+ RSpec::Matchers.define :be_found do
57
+
58
+ match do |exchange|
59
+ expect(exchange.exchange_handler.found?(exchange.response)).to be true
60
+ end
61
+
62
+ failure_message do |exchange|
63
+ "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}"
64
+ end
65
+
66
66
  end
@@ -1,13 +1,13 @@
1
- # Raised to represent when there's no element at an Xpath
2
- class NoElementAtPath < StandardError
3
- def initialize(msg = 'No element at path found')
4
- super
5
- end
6
- end
7
-
8
- # Did not find any element by provided key in the Hash
9
- class NoElementInHash < StandardError
10
- def initialize(msg = 'No element in Hash found')
11
- super
12
- end
13
- end
1
+ # Raised to represent when there's no element at an Xpath
2
+ class NoElementAtPath < StandardError
3
+ def initialize(msg = 'No element at path found')
4
+ super
5
+ end
6
+ end
7
+
8
+ # Did not find any element by provided key in the Hash
9
+ class NoElementInHash < StandardError
10
+ def initialize(msg = 'No element in Hash found')
11
+ super
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+ require 'erb'
2
+
3
+ module Soaspec
4
+ # Handles working with OAuth2
5
+ class OAuth2
6
+ attr_accessor :params
7
+ # Count of tries to obtain access token
8
+ attr_accessor :retry_count
9
+
10
+ # @param [Hash] params Parameters to make OAuth request
11
+ # @param [String] api_username Username to use which can be set by Soaspec::ExchangeHandler
12
+ def initialize(params, api_username)
13
+ raise 'client_id and client_secret not set' unless params[:client_id] && params[:client_secret]
14
+ self.params = params
15
+ params[:username] = api_username || ERB.new(params[:username]).result(binding) if params[:username]
16
+ params[:security_token] = ERB.new(params[:security_token]).result(binding) if params[:security_token]
17
+ params[:token_url] = ERB.new(params[:token_url]).result(binding) if params[:token_url]
18
+ params[:password] = ERB.new(params[:password]).result(binding) if params[:password]
19
+ Soaspec::SpecLogger.info request_message
20
+ end
21
+
22
+ # @return [Hash] Hash containing access token parameters
23
+ def response
24
+ response = RestClient.post(params[:token_url], payload, cache_control: 'no_cache', verify_ssl: false)
25
+ rescue RestClient::Exception => error
26
+ Soaspec::SpecLogger.info(["oauth_error: #{error.message}", "oauth_response: #{error.response}"])
27
+ self.retry_count += 1
28
+ sleep 0.1 # Wait if a bit before retying obtaining access token
29
+ retry if retry_count < 3
30
+ raise error
31
+ else
32
+ Soaspec::SpecLogger.info(["response_headers: #{response.headers}", "response_body: #{response.body}"]) if Soaspec.debug_oauth?
33
+ JSON.parse(response)
34
+ end
35
+
36
+ # @return [String] String to represent OAuth for logging logs
37
+ def request_message
38
+ if Soaspec.debug_oauth?
39
+ "request_params: #{payload}"
40
+ else
41
+ params[:username] ? "User '#{params[:username]}'" : 'client_credentials'
42
+ end
43
+ end
44
+
45
+ # @return [String] Password to use in OAuth request
46
+ def password
47
+ params[:security_token] ? (params[:password] + params[:security_token]) : params[:password]
48
+ end
49
+
50
+ # Payload to add to o-auth request dependent on params provided
51
+ # @return [Hash] Payload for retrieving OAuth access token
52
+ def payload
53
+ payload = { client_id: params[:client_id], client_secret: params[:client_secret] }
54
+ payload.merge(if params[:password] && params[:username]
55
+ {
56
+ grant_type: 'password', username: params[:username],
57
+ password: password, multipart: true
58
+ }
59
+ else
60
+ { grant_type: 'client_credentials' }
61
+ end)
62
+ end
63
+
64
+ end
65
+ end
@@ -1,24 +1,24 @@
1
- require 'rspec'
2
-
3
- shared_examples_for 'success scenario' do
4
- it 'has successful status code' do
5
- expect(200..299).to cover described_class.status_code
6
- end
7
- context 'has expected mandatory elements' do
8
- described_class.exchange_handler.expected_mandatory_elements.each do |mandatory_element|
9
- it mandatory_element do
10
- expect(described_class).to contain_key mandatory_element
11
- end
12
- end
13
- end
14
- described_class.exchange_handler.expected_mandatory_xpath_values.each do |xpath, value|
15
- it "has xpath '#{xpath}' equal to '#{value}'" do
16
- expect(described_class).to have_xpath_value(xpath => value)
17
- end
18
- end
19
- described_class.exchange_handler.expected_mandatory_json_values.each do |xpath, value|
20
- it "has xpath '#{xpath}' equal to '#{value}'" do
21
- expect(described_class).to have_xpath_value(xpath => value)
22
- end
23
- end
24
- end
1
+ require 'rspec'
2
+
3
+ shared_examples_for 'success scenario' do
4
+ it 'has successful status code' do
5
+ expect(200..299).to cover described_class.status_code
6
+ end
7
+ context 'has expected mandatory elements' do
8
+ described_class.exchange_handler.expected_mandatory_elements.each do |mandatory_element|
9
+ it mandatory_element do
10
+ expect(described_class).to contain_key mandatory_element
11
+ end
12
+ end
13
+ end
14
+ described_class.exchange_handler.expected_mandatory_xpath_values.each do |xpath, value|
15
+ it "has xpath '#{xpath}' equal to '#{value}'" do
16
+ expect(described_class).to have_xpath_value(xpath => value)
17
+ end
18
+ end
19
+ described_class.exchange_handler.expected_mandatory_json_values.each do |xpath, value|
20
+ it "has xpath '#{xpath}' equal to '#{value}'" do
21
+ expect(described_class).to have_xpath_value(xpath => value)
22
+ end
23
+ end
24
+ end
@@ -1,28 +1,35 @@
1
-
2
- require 'logger'
3
- require 'fileutils'
4
-
5
- module Soaspec
6
-
7
- # Handles logs of API requests and responses
8
- class SpecLogger
9
- class << self
10
- def create
11
- unless File.exist?('logs/traffic.log')
12
- FileUtils.mkdir_p 'logs'
13
- FileUtils.touch File.join('logs', 'traffic.log')
14
- end
15
- @logger = Logger.new('logs/traffic.log') # Where request and responses of APIs are stored
16
- @logger.level = Logger::DEBUG
17
- @logger
18
- end
19
-
20
- # Log a message using Soaspec logger
21
- # @param [String] message The message to add to the logger
22
- def info(message)
23
- @logger.info(message) if Soaspec.log_api_traffic?
24
- end
25
- end
26
-
27
- end
1
+
2
+ require 'logger'
3
+ require 'fileutils'
4
+
5
+ module Soaspec
6
+
7
+ # Handles logs of API requests and responses
8
+ class SpecLogger
9
+ class << self
10
+ def create
11
+ unless File.exist?('logs/traffic.log')
12
+ FileUtils.mkdir_p 'logs'
13
+ FileUtils.touch File.join('logs', 'traffic.log')
14
+ end
15
+ @logger = Logger.new('logs/traffic.log') # Where request and responses of APIs are stored
16
+ @logger.level = Logger::DEBUG
17
+ @logger
18
+ end
19
+
20
+ # Log a message using Soaspec logger
21
+ # @param [String] message The message to add to the logger
22
+ def info(message)
23
+ return unless Soaspec.log_api_traffic?
24
+ if message.respond_to? :each
25
+ message.each do |message_item|
26
+ @logger.info(message_item)
27
+ end
28
+ else
29
+ @logger.info(message)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
28
35
  end