soaspec 0.2.33 → 0.3.1
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 +4 -4
- data/.gitignore +15 -15
- data/.gitlab-ci.yml +62 -62
- data/.rspec +3 -3
- data/.rubocop.yml +2 -2
- data/CODE_OF_CONDUCT.md +74 -74
- data/ChangeLog +643 -632
- data/Dockerfile +7 -7
- data/Gemfile +8 -8
- data/LICENSE.txt +21 -21
- data/README.md +253 -231
- data/Rakefile +52 -52
- data/Todo.md +16 -16
- data/exe/soaspec +140 -138
- data/exe/xml_to_yaml_file +43 -43
- data/lib/soaspec.rb +118 -106
- data/lib/soaspec/baseline.rb +82 -22
- data/lib/soaspec/core_ext/hash.rb +44 -44
- data/lib/soaspec/cucumber/generic_steps.rb +94 -94
- data/lib/soaspec/demo.rb +6 -6
- data/lib/soaspec/errors.rb +24 -24
- data/lib/soaspec/exchange/exchange.rb +131 -129
- data/lib/soaspec/exchange/exchange_extractor.rb +105 -90
- data/lib/soaspec/exchange/exchange_properties.rb +28 -28
- data/lib/soaspec/exchange/exchange_repeater.rb +21 -21
- data/lib/soaspec/exchange/request_builder.rb +108 -70
- data/lib/soaspec/exchange/variable_storer.rb +24 -24
- data/lib/soaspec/exchange_handlers/exchange_handler.rb +98 -98
- data/lib/soaspec/exchange_handlers/exchange_handler_defaults.rb +61 -61
- data/lib/soaspec/exchange_handlers/handler_accessors.rb +132 -132
- data/lib/soaspec/exchange_handlers/request/rest_request.rb +77 -59
- data/lib/soaspec/exchange_handlers/request/soap_request.rb +41 -41
- data/lib/soaspec/exchange_handlers/response_extractor.rb +84 -84
- data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +111 -111
- data/lib/soaspec/exchange_handlers/rest_handler.rb +307 -307
- data/lib/soaspec/exchange_handlers/rest_methods.rb +65 -65
- data/lib/soaspec/exchange_handlers/rest_parameters.rb +112 -112
- data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +42 -42
- data/lib/soaspec/exchange_handlers/soap_handler.rb +241 -241
- data/lib/soaspec/exe_helpers.rb +94 -94
- data/lib/soaspec/generate_server.rb +48 -48
- data/lib/soaspec/generator/.rspec.erb +5 -5
- data/lib/soaspec/generator/.travis.yml.erb +5 -5
- data/lib/soaspec/generator/Gemfile.erb +8 -8
- data/lib/soaspec/generator/README.md.erb +29 -29
- data/lib/soaspec/generator/Rakefile.erb +20 -19
- data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
- data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
- data/lib/soaspec/generator/features/support/env.rb.erb +3 -3
- data/lib/soaspec/generator/generate_exchange.html.erb +47 -47
- data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
- data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
- data/lib/soaspec/generator/lib/new_rest_service.rb.erb +56 -56
- data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
- data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
- data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
- data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
- data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
- data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
- data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
- data/lib/soaspec/generator/template/soap_template.xml +6 -6
- data/lib/soaspec/indifferent_hash.rb +9 -9
- data/lib/soaspec/interpreter.rb +70 -70
- data/lib/soaspec/matchers.rb +136 -140
- data/lib/soaspec/o_auth2.rb +142 -142
- data/lib/soaspec/soaspec_shared_examples.rb +26 -26
- data/lib/soaspec/spec_logger.rb +143 -143
- data/lib/soaspec/template_reader.rb +30 -30
- data/lib/soaspec/test_server/bank.wsdl +90 -90
- data/lib/soaspec/test_server/get_bank.rb +166 -166
- data/lib/soaspec/test_server/id_manager.rb +41 -41
- data/lib/soaspec/test_server/invoices.rb +29 -29
- data/lib/soaspec/test_server/namespace.xml +14 -14
- data/lib/soaspec/test_server/note.xml +5 -5
- data/lib/soaspec/test_server/puppy_service.rb +21 -21
- data/lib/soaspec/test_server/test_attribute.rb +14 -14
- data/lib/soaspec/test_server/test_namespace.rb +14 -14
- data/lib/soaspec/version.rb +6 -6
- data/lib/soaspec/virtual_server.rb +193 -190
- data/lib/soaspec/wait.rb +43 -43
- data/lib/soaspec/wsdl_generator.rb +215 -215
- data/soaspec.gemspec +58 -58
- data/test.wsdl +116 -116
- data/test.xml +10 -10
- data/test_wsdl.rb +43 -43
- metadata +3 -3
data/lib/soaspec/o_auth2.rb
CHANGED
@@ -1,142 +1,142 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'erb'
|
4
|
-
|
5
|
-
module Soaspec
|
6
|
-
# Handles working with OAuth2
|
7
|
-
class OAuth2
|
8
|
-
# How often to refresh access token
|
9
|
-
@refresh_token = :always
|
10
|
-
# List of access tokens. They are mapped according to the OAuth parameters used
|
11
|
-
@access_tokens = {}
|
12
|
-
# List of instance URLs. They are mapped according to the OAuth parameters used
|
13
|
-
@instance_urls = {}
|
14
|
-
# Whether to see params sent to & received from oauth URL
|
15
|
-
@request_message = true
|
16
|
-
# How many times to attempt to authenticate before raising exception
|
17
|
-
@retry_limit = 2
|
18
|
-
class << self
|
19
|
-
# Default token url used across entire suite
|
20
|
-
attr_accessor :token_url
|
21
|
-
# @attr [Symbol] refresh_token How often to refresh access token
|
22
|
-
# Values are:
|
23
|
-
# * :always - (Default) Request token from token url every time it is needed
|
24
|
-
# * :once - Request token once for the entire execution of the suite
|
25
|
-
attr_accessor :refresh_token
|
26
|
-
# @attr [Hash] access_tokens List of access tokens. They are mapped according to the OAuth parameters used
|
27
|
-
attr_accessor :access_tokens
|
28
|
-
# List of URLs to that define the instance of an application
|
29
|
-
attr_accessor :instance_urls
|
30
|
-
# Specify whether to see params sent to and retrieved from oauth. This will put password in log file, only recommended for debugging
|
31
|
-
attr_writer :debug_oauth
|
32
|
-
# @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
|
33
|
-
attr_writer :request_message
|
34
|
-
# @return [Integer] How many times to attempt to authenticate before raising exception
|
35
|
-
attr_accessor :retry_limit
|
36
|
-
# @return [Boolean] Whether to see params sent to & received from oauth URL
|
37
|
-
def debug_oauth?
|
38
|
-
@debug_oauth || false
|
39
|
-
end
|
40
|
-
|
41
|
-
# @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
|
42
|
-
def request_message?
|
43
|
-
@request_message
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# @attr [Hash] OAuth parameters
|
48
|
-
attr_accessor :params
|
49
|
-
# @attr [Integer] Count of tries to obtain access token
|
50
|
-
attr_accessor :retry_count
|
51
|
-
|
52
|
-
# @param [Hash] params_sent Parameters to make OAuth request
|
53
|
-
# @option params_sent [token_url] URL to retrieve OAuth token from. @Note this can be set globally instead of here
|
54
|
-
# @option params_sent [client_id] Client ID
|
55
|
-
# @option params_sent [client_secret] Client Secret
|
56
|
-
# @option params_sent [username] Username used in password grant
|
57
|
-
# @option params_sent [password] Password used in password grant
|
58
|
-
# @option params_sent [security_token] Security Token used in password grant
|
59
|
-
# @param [String] api_username Username to use which can be set by Soaspec::ExchangeHandler
|
60
|
-
def initialize(params_sent, api_username = nil)
|
61
|
-
self.retry_count = 0 # No initial tries at getting access token
|
62
|
-
params = params_sent.transform_keys_to_symbols
|
63
|
-
params[:token_url] ||= Soaspec::OAuth2.token_url
|
64
|
-
raise ArgumentError, 'client_id and client_secret not set' unless params[:client_id] && params[:client_secret]
|
65
|
-
raise ArgumentError, 'token_url mandatory' unless params[:token_url]
|
66
|
-
|
67
|
-
self.params = params
|
68
|
-
params[:username] = api_username || ERB.new(params[:username]).result(binding) if params[:username]
|
69
|
-
params[:security_token] = ERB.new(params[:security_token]).result(binding) if params[:security_token]
|
70
|
-
params[:token_url] = ERB.new(params[:token_url]).result(binding) if params[:token_url]
|
71
|
-
params[:password] = ERB.new(params[:password]).result(binding) if params[:password]
|
72
|
-
end
|
73
|
-
|
74
|
-
# Retrieve whether to debug oauth parameters based on global settings
|
75
|
-
# @return [Boolean] Whether to see params sent to & received from oauth URL
|
76
|
-
def debug_oauth?
|
77
|
-
self.class.debug_oauth?
|
78
|
-
end
|
79
|
-
|
80
|
-
# Retrieve instance_url according to access token response.
|
81
|
-
# Some applications have a different instance
|
82
|
-
# It's assumed this will be constant for a set of oauth parameters
|
83
|
-
# @return [String] Instance url
|
84
|
-
def instance_url
|
85
|
-
Soaspec::OAuth2.instance_urls[params] ||= response['instance_url']
|
86
|
-
end
|
87
|
-
|
88
|
-
# @return [String] Existing or new access token, dependent on refresh_token attribute
|
89
|
-
def access_token
|
90
|
-
Soaspec::SpecLogger.info request_message if self.class.request_message?
|
91
|
-
case Soaspec::OAuth2.refresh_token
|
92
|
-
when :once
|
93
|
-
Soaspec::OAuth2.access_tokens[params] ||= response['access_token']
|
94
|
-
else # Default is :always
|
95
|
-
response['access_token']
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# @return [Hash] Hash containing access token parameters
|
100
|
-
def response
|
101
|
-
Soaspec::SpecLogger.info "using oauth_params: #{params}" if debug_oauth?
|
102
|
-
response = RestClient.post(params[:token_url], payload, cache_control: 'no_cache', verify_ssl: false)
|
103
|
-
rescue RestClient::Exception => e
|
104
|
-
Soaspec::SpecLogger.info(["oauth_error: #{e.message}", "oauth_response: #{e.response}"])
|
105
|
-
self.retry_count += 1
|
106
|
-
sleep 0.1 # Wait if a bit before retying obtaining access token
|
107
|
-
retry if retry_count < self.class.retry_limit
|
108
|
-
raise e
|
109
|
-
else
|
110
|
-
Soaspec::SpecLogger.info(["response: \n headers: #{response&.headers}\n body: #{response}\n"]) if debug_oauth?
|
111
|
-
JSON.parse(response)
|
112
|
-
end
|
113
|
-
|
114
|
-
# @return [String] String to represent OAuth for logging logs
|
115
|
-
def request_message
|
116
|
-
if debug_oauth?
|
117
|
-
"request_params: #{payload}"
|
118
|
-
else
|
119
|
-
params[:username] ? "User '#{params[:username]}'" : 'client_credentials'
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# @return [String] Password to use in OAuth request
|
124
|
-
def password
|
125
|
-
params[:security_token] ? (params[:password] + params[:security_token]) : params[:password]
|
126
|
-
end
|
127
|
-
|
128
|
-
# Payload to add to o-auth request dependent on params provided
|
129
|
-
# @return [Hash] Payload for retrieving OAuth access token
|
130
|
-
def payload
|
131
|
-
payload = { client_id: params[:client_id], client_secret: params[:client_secret] }
|
132
|
-
payload.merge(if params[:password] && params[:username]
|
133
|
-
{
|
134
|
-
grant_type: 'password', username: params[:username],
|
135
|
-
password: password, multipart: true
|
136
|
-
}
|
137
|
-
else
|
138
|
-
{ grant_type: 'client_credentials' }
|
139
|
-
end)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module Soaspec
|
6
|
+
# Handles working with OAuth2
|
7
|
+
class OAuth2
|
8
|
+
# How often to refresh access token
|
9
|
+
@refresh_token = :always
|
10
|
+
# List of access tokens. They are mapped according to the OAuth parameters used
|
11
|
+
@access_tokens = {}
|
12
|
+
# List of instance URLs. They are mapped according to the OAuth parameters used
|
13
|
+
@instance_urls = {}
|
14
|
+
# Whether to see params sent to & received from oauth URL
|
15
|
+
@request_message = true
|
16
|
+
# How many times to attempt to authenticate before raising exception
|
17
|
+
@retry_limit = 2
|
18
|
+
class << self
|
19
|
+
# Default token url used across entire suite
|
20
|
+
attr_accessor :token_url
|
21
|
+
# @attr [Symbol] refresh_token How often to refresh access token
|
22
|
+
# Values are:
|
23
|
+
# * :always - (Default) Request token from token url every time it is needed
|
24
|
+
# * :once - Request token once for the entire execution of the suite
|
25
|
+
attr_accessor :refresh_token
|
26
|
+
# @attr [Hash] access_tokens List of access tokens. They are mapped according to the OAuth parameters used
|
27
|
+
attr_accessor :access_tokens
|
28
|
+
# List of URLs to that define the instance of an application
|
29
|
+
attr_accessor :instance_urls
|
30
|
+
# Specify whether to see params sent to and retrieved from oauth. This will put password in log file, only recommended for debugging
|
31
|
+
attr_writer :debug_oauth
|
32
|
+
# @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
|
33
|
+
attr_writer :request_message
|
34
|
+
# @return [Integer] How many times to attempt to authenticate before raising exception
|
35
|
+
attr_accessor :retry_limit
|
36
|
+
# @return [Boolean] Whether to see params sent to & received from oauth URL
|
37
|
+
def debug_oauth?
|
38
|
+
@debug_oauth || false
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
|
42
|
+
def request_message?
|
43
|
+
@request_message
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @attr [Hash] OAuth parameters
|
48
|
+
attr_accessor :params
|
49
|
+
# @attr [Integer] Count of tries to obtain access token
|
50
|
+
attr_accessor :retry_count
|
51
|
+
|
52
|
+
# @param [Hash] params_sent Parameters to make OAuth request
|
53
|
+
# @option params_sent [token_url] URL to retrieve OAuth token from. @Note this can be set globally instead of here
|
54
|
+
# @option params_sent [client_id] Client ID
|
55
|
+
# @option params_sent [client_secret] Client Secret
|
56
|
+
# @option params_sent [username] Username used in password grant
|
57
|
+
# @option params_sent [password] Password used in password grant
|
58
|
+
# @option params_sent [security_token] Security Token used in password grant
|
59
|
+
# @param [String] api_username Username to use which can be set by Soaspec::ExchangeHandler
|
60
|
+
def initialize(params_sent, api_username = nil)
|
61
|
+
self.retry_count = 0 # No initial tries at getting access token
|
62
|
+
params = params_sent.transform_keys_to_symbols
|
63
|
+
params[:token_url] ||= Soaspec::OAuth2.token_url
|
64
|
+
raise ArgumentError, 'client_id and client_secret not set' unless params[:client_id] && params[:client_secret]
|
65
|
+
raise ArgumentError, 'token_url mandatory' unless params[:token_url]
|
66
|
+
|
67
|
+
self.params = params
|
68
|
+
params[:username] = api_username || ERB.new(params[:username]).result(binding) if params[:username]
|
69
|
+
params[:security_token] = ERB.new(params[:security_token]).result(binding) if params[:security_token]
|
70
|
+
params[:token_url] = ERB.new(params[:token_url]).result(binding) if params[:token_url]
|
71
|
+
params[:password] = ERB.new(params[:password]).result(binding) if params[:password]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Retrieve whether to debug oauth parameters based on global settings
|
75
|
+
# @return [Boolean] Whether to see params sent to & received from oauth URL
|
76
|
+
def debug_oauth?
|
77
|
+
self.class.debug_oauth?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Retrieve instance_url according to access token response.
|
81
|
+
# Some applications have a different instance
|
82
|
+
# It's assumed this will be constant for a set of oauth parameters
|
83
|
+
# @return [String] Instance url
|
84
|
+
def instance_url
|
85
|
+
Soaspec::OAuth2.instance_urls[params] ||= response['instance_url']
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [String] Existing or new access token, dependent on refresh_token attribute
|
89
|
+
def access_token
|
90
|
+
Soaspec::SpecLogger.info request_message if self.class.request_message?
|
91
|
+
case Soaspec::OAuth2.refresh_token
|
92
|
+
when :once
|
93
|
+
Soaspec::OAuth2.access_tokens[params] ||= response['access_token']
|
94
|
+
else # Default is :always
|
95
|
+
response['access_token']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [Hash] Hash containing access token parameters
|
100
|
+
def response
|
101
|
+
Soaspec::SpecLogger.info "using oauth_params: #{params}" if debug_oauth?
|
102
|
+
response = RestClient.post(params[:token_url], payload, cache_control: 'no_cache', verify_ssl: false)
|
103
|
+
rescue RestClient::Exception => e
|
104
|
+
Soaspec::SpecLogger.info(["oauth_error: #{e.message}", "oauth_response: #{e.response}"])
|
105
|
+
self.retry_count += 1
|
106
|
+
sleep 0.1 # Wait if a bit before retying obtaining access token
|
107
|
+
retry if retry_count < self.class.retry_limit
|
108
|
+
raise e
|
109
|
+
else
|
110
|
+
Soaspec::SpecLogger.info(["response: \n headers: #{response&.headers}\n body: #{response}\n"]) if debug_oauth?
|
111
|
+
JSON.parse(response)
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [String] String to represent OAuth for logging logs
|
115
|
+
def request_message
|
116
|
+
if debug_oauth?
|
117
|
+
"request_params: #{payload}"
|
118
|
+
else
|
119
|
+
params[:username] ? "User '#{params[:username]}'" : 'client_credentials'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @return [String] Password to use in OAuth request
|
124
|
+
def password
|
125
|
+
params[:security_token] ? (params[:password] + params[:security_token]) : params[:password]
|
126
|
+
end
|
127
|
+
|
128
|
+
# Payload to add to o-auth request dependent on params provided
|
129
|
+
# @return [Hash] Payload for retrieving OAuth access token
|
130
|
+
def payload
|
131
|
+
payload = { client_id: params[:client_id], client_secret: params[:client_secret] }
|
132
|
+
payload.merge(if params[:password] && params[:username]
|
133
|
+
{
|
134
|
+
grant_type: 'password', username: params[:username],
|
135
|
+
password: password, multipart: true
|
136
|
+
}
|
137
|
+
else
|
138
|
+
{ grant_type: 'client_credentials' }
|
139
|
+
end)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -1,26 +1,26 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rspec'
|
4
|
-
|
5
|
-
RSpec.shared_examples_for 'success scenario' do
|
6
|
-
it 'has successful status code' do
|
7
|
-
expect(described_class.successful_status_code?).to be true
|
8
|
-
end
|
9
|
-
context 'has expected mandatory elements' do
|
10
|
-
described_class.exchange_handler.expected_mandatory_elements.each do |mandatory_element|
|
11
|
-
it mandatory_element do
|
12
|
-
expect(described_class).to contain_key mandatory_element
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
described_class.exchange_handler.expected_mandatory_xpath_values.each do |xpath, value|
|
17
|
-
it "has xpath '#{xpath}' equal to '#{value}'" do
|
18
|
-
expect(described_class).to have_xpath_value(xpath => value)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
described_class.exchange_handler.expected_mandatory_json_values.each do |xpath, value|
|
22
|
-
it "has json '#{xpath}' equal to '#{value}'" do
|
23
|
-
expect(described_class).to have_xpath_value(xpath => value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
RSpec.shared_examples_for 'success scenario' do
|
6
|
+
it 'has successful status code' do
|
7
|
+
expect(described_class.successful_status_code?).to be true
|
8
|
+
end
|
9
|
+
context 'has expected mandatory elements' do
|
10
|
+
described_class.exchange_handler.expected_mandatory_elements.each do |mandatory_element|
|
11
|
+
it mandatory_element do
|
12
|
+
expect(described_class).to contain_key mandatory_element
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
described_class.exchange_handler.expected_mandatory_xpath_values.each do |xpath, value|
|
17
|
+
it "has xpath '#{xpath}' equal to '#{value}'" do
|
18
|
+
expect(described_class).to have_xpath_value(xpath => value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
described_class.exchange_handler.expected_mandatory_json_values.each do |xpath, value|
|
22
|
+
it "has json '#{xpath}' equal to '#{value}'" do
|
23
|
+
expect(described_class).to have_xpath_value(xpath => value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/soaspec/spec_logger.rb
CHANGED
@@ -1,143 +1,143 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'logger'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'colorize'
|
6
|
-
|
7
|
-
module Soaspec
|
8
|
-
# Custom class for logging API traffic
|
9
|
-
class ApiLogger < Logger
|
10
|
-
#
|
11
|
-
# Rewrite << to use info logger with formatting
|
12
|
-
#
|
13
|
-
def <<(msg)
|
14
|
-
info msg
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Handles logs of API requests and responses
|
19
|
-
class SpecLogger
|
20
|
-
# Folder to put API traffic logs
|
21
|
-
@traffic_folder = 'logs'
|
22
|
-
# Whether to output api traffic to terminal
|
23
|
-
@output_to_terminal = false
|
24
|
-
# Color shown when displaying in terminal
|
25
|
-
@terminal_color = :light_blue
|
26
|
-
# Whether to output API traffic to log file
|
27
|
-
@output_to_file = true
|
28
|
-
# Time test run. Will only be calculated once once called
|
29
|
-
@time_test_run = Time.now.strftime('%Y-%m-%d_%H_%M_%S')
|
30
|
-
# By default file is based on time
|
31
|
-
@traffic_file = nil
|
32
|
-
# Name of program to include in logs
|
33
|
-
@progname
|
34
|
-
class << self
|
35
|
-
# Folder to put API traffic logs
|
36
|
-
attr_accessor :traffic_folder
|
37
|
-
# Color shown when displaying in terminal
|
38
|
-
attr_accessor :terminal_color
|
39
|
-
# Readers for log parameters
|
40
|
-
attr_reader :output_to_terminal, :output_to_file, :time_test_run
|
41
|
-
# @return [String] Name of program to include in logs
|
42
|
-
attr_accessor :progname
|
43
|
-
# @return [String] String representing date format to use for traffic
|
44
|
-
attr_writer :time_format
|
45
|
-
# Logger used to log API requests
|
46
|
-
attr_accessor :logger
|
47
|
-
|
48
|
-
# String representing date format to use for traffic
|
49
|
-
def time_format
|
50
|
-
@time_format || '%H:%M:%S'
|
51
|
-
end
|
52
|
-
|
53
|
-
# Set file to log traffic to
|
54
|
-
# @param [String] file Path to traffic file to use
|
55
|
-
def traffic_file=(file)
|
56
|
-
@traffic_file = file
|
57
|
-
reset_log
|
58
|
-
end
|
59
|
-
|
60
|
-
# @return [String] Traffic file to create logs at
|
61
|
-
def traffic_file
|
62
|
-
return File.join(traffic_folder, @traffic_file) if @traffic_file
|
63
|
-
|
64
|
-
filename = "traffic_#{time_test_run}.log"
|
65
|
-
File.join(traffic_folder, filename)
|
66
|
-
end
|
67
|
-
|
68
|
-
# Unset Logger object. It will be recreated on next time 'info' is called
|
69
|
-
def reset_log
|
70
|
-
@logger = nil
|
71
|
-
RestClient.log = nil
|
72
|
-
end
|
73
|
-
|
74
|
-
# Whether to log all API traffic
|
75
|
-
def log_api_traffic=(set)
|
76
|
-
@log_api_traffic = set
|
77
|
-
reset_log
|
78
|
-
end
|
79
|
-
|
80
|
-
# @return [Boolean] Whether to log all API traffic
|
81
|
-
def log_api_traffic?
|
82
|
-
@log_api_traffic.nil? ? true : @log_api_traffic
|
83
|
-
end
|
84
|
-
|
85
|
-
# @param [Symbol, Boolean] value # Whether to output API traffic to log file
|
86
|
-
def output_to_file=(value)
|
87
|
-
@output_to_file = value
|
88
|
-
reset_log
|
89
|
-
end
|
90
|
-
|
91
|
-
# @param [Symbol, Boolean] value # Whether to output API traffic to STDOUT
|
92
|
-
def output_to_terminal=(value)
|
93
|
-
@output_to_terminal = value
|
94
|
-
reset_log
|
95
|
-
end
|
96
|
-
|
97
|
-
# Create new log file if necessary and setup logging level
|
98
|
-
# @return [Logger] Logger class to record API traffic
|
99
|
-
def create
|
100
|
-
create_log_file
|
101
|
-
@logger = ApiLogger.new(traffic_file) # Where request and responses of APIs are stored
|
102
|
-
@logger.progname = progname || 'SpecLog'
|
103
|
-
@logger.formatter = proc do |_severity, datetime, progname, msg|
|
104
|
-
message = "#{progname}, [#{datetime.strftime(time_format)}] : #{msg}\n"
|
105
|
-
print message.colorize(terminal_color) if @output_to_terminal
|
106
|
-
message if @output_to_file
|
107
|
-
end
|
108
|
-
RestClient.log = @logger
|
109
|
-
@logger
|
110
|
-
end
|
111
|
-
|
112
|
-
# Log a message using Soaspec logger
|
113
|
-
# Logger (and it's file) will be created if it's not already set
|
114
|
-
# @param [String, Array] message The message to add to the logger or list of messages
|
115
|
-
def info(message)
|
116
|
-
return unless log_api_traffic?
|
117
|
-
|
118
|
-
create unless @logger
|
119
|
-
if message.respond_to? :each
|
120
|
-
message.each do |message_item|
|
121
|
-
info(message_item)
|
122
|
-
end
|
123
|
-
else
|
124
|
-
if block_given?
|
125
|
-
@logger.info(message) { yield }
|
126
|
-
else
|
127
|
-
@logger.info(message)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
# Create folder and file to store logs
|
135
|
-
def create_log_file
|
136
|
-
return if File.exist?(traffic_file)
|
137
|
-
|
138
|
-
FileUtils.mkdir_p traffic_folder
|
139
|
-
FileUtils.touch traffic_file
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'colorize'
|
6
|
+
|
7
|
+
module Soaspec
|
8
|
+
# Custom class for logging API traffic
|
9
|
+
class ApiLogger < Logger
|
10
|
+
#
|
11
|
+
# Rewrite << to use info logger with formatting
|
12
|
+
#
|
13
|
+
def <<(msg)
|
14
|
+
info msg
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Handles logs of API requests and responses
|
19
|
+
class SpecLogger
|
20
|
+
# Folder to put API traffic logs
|
21
|
+
@traffic_folder = 'logs'
|
22
|
+
# Whether to output api traffic to terminal
|
23
|
+
@output_to_terminal = false
|
24
|
+
# Color shown when displaying in terminal
|
25
|
+
@terminal_color = :light_blue
|
26
|
+
# Whether to output API traffic to log file
|
27
|
+
@output_to_file = true
|
28
|
+
# Time test run. Will only be calculated once once called
|
29
|
+
@time_test_run = Time.now.strftime('%Y-%m-%d_%H_%M_%S')
|
30
|
+
# By default file is based on time
|
31
|
+
@traffic_file = nil
|
32
|
+
# Name of program to include in logs
|
33
|
+
@progname
|
34
|
+
class << self
|
35
|
+
# Folder to put API traffic logs
|
36
|
+
attr_accessor :traffic_folder
|
37
|
+
# Color shown when displaying in terminal
|
38
|
+
attr_accessor :terminal_color
|
39
|
+
# Readers for log parameters
|
40
|
+
attr_reader :output_to_terminal, :output_to_file, :time_test_run
|
41
|
+
# @return [String] Name of program to include in logs
|
42
|
+
attr_accessor :progname
|
43
|
+
# @return [String] String representing date format to use for traffic
|
44
|
+
attr_writer :time_format
|
45
|
+
# Logger used to log API requests
|
46
|
+
attr_accessor :logger
|
47
|
+
|
48
|
+
# String representing date format to use for traffic
|
49
|
+
def time_format
|
50
|
+
@time_format || '%H:%M:%S'
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set file to log traffic to
|
54
|
+
# @param [String] file Path to traffic file to use
|
55
|
+
def traffic_file=(file)
|
56
|
+
@traffic_file = file
|
57
|
+
reset_log
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [String] Traffic file to create logs at
|
61
|
+
def traffic_file
|
62
|
+
return File.join(traffic_folder, @traffic_file) if @traffic_file
|
63
|
+
|
64
|
+
filename = "traffic_#{time_test_run}.log"
|
65
|
+
File.join(traffic_folder, filename)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Unset Logger object. It will be recreated on next time 'info' is called
|
69
|
+
def reset_log
|
70
|
+
@logger = nil
|
71
|
+
RestClient.log = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Whether to log all API traffic
|
75
|
+
def log_api_traffic=(set)
|
76
|
+
@log_api_traffic = set
|
77
|
+
reset_log
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Boolean] Whether to log all API traffic
|
81
|
+
def log_api_traffic?
|
82
|
+
@log_api_traffic.nil? ? true : @log_api_traffic
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param [Symbol, Boolean] value # Whether to output API traffic to log file
|
86
|
+
def output_to_file=(value)
|
87
|
+
@output_to_file = value
|
88
|
+
reset_log
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param [Symbol, Boolean] value # Whether to output API traffic to STDOUT
|
92
|
+
def output_to_terminal=(value)
|
93
|
+
@output_to_terminal = value
|
94
|
+
reset_log
|
95
|
+
end
|
96
|
+
|
97
|
+
# Create new log file if necessary and setup logging level
|
98
|
+
# @return [Logger] Logger class to record API traffic
|
99
|
+
def create
|
100
|
+
create_log_file
|
101
|
+
@logger = ApiLogger.new(traffic_file) # Where request and responses of APIs are stored
|
102
|
+
@logger.progname = progname || 'SpecLog'
|
103
|
+
@logger.formatter = proc do |_severity, datetime, progname, msg|
|
104
|
+
message = "#{progname}, [#{datetime.strftime(time_format)}] : #{msg}\n"
|
105
|
+
print message.colorize(terminal_color) if @output_to_terminal
|
106
|
+
message if @output_to_file
|
107
|
+
end
|
108
|
+
RestClient.log = @logger
|
109
|
+
@logger
|
110
|
+
end
|
111
|
+
|
112
|
+
# Log a message using Soaspec logger
|
113
|
+
# Logger (and it's file) will be created if it's not already set
|
114
|
+
# @param [String, Array] message The message to add to the logger or list of messages
|
115
|
+
def info(message)
|
116
|
+
return unless log_api_traffic?
|
117
|
+
|
118
|
+
create unless @logger
|
119
|
+
if message.respond_to? :each
|
120
|
+
message.each do |message_item|
|
121
|
+
info(message_item)
|
122
|
+
end
|
123
|
+
else
|
124
|
+
if block_given?
|
125
|
+
@logger.info(message) { yield }
|
126
|
+
else
|
127
|
+
@logger.info(message)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
# Create folder and file to store logs
|
135
|
+
def create_log_file
|
136
|
+
return if File.exist?(traffic_file)
|
137
|
+
|
138
|
+
FileUtils.mkdir_p traffic_folder
|
139
|
+
FileUtils.touch traffic_file
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|