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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +62 -62
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +643 -632
  8. data/Dockerfile +7 -7
  9. data/Gemfile +8 -8
  10. data/LICENSE.txt +21 -21
  11. data/README.md +253 -231
  12. data/Rakefile +52 -52
  13. data/Todo.md +16 -16
  14. data/exe/soaspec +140 -138
  15. data/exe/xml_to_yaml_file +43 -43
  16. data/lib/soaspec.rb +118 -106
  17. data/lib/soaspec/baseline.rb +82 -22
  18. data/lib/soaspec/core_ext/hash.rb +44 -44
  19. data/lib/soaspec/cucumber/generic_steps.rb +94 -94
  20. data/lib/soaspec/demo.rb +6 -6
  21. data/lib/soaspec/errors.rb +24 -24
  22. data/lib/soaspec/exchange/exchange.rb +131 -129
  23. data/lib/soaspec/exchange/exchange_extractor.rb +105 -90
  24. data/lib/soaspec/exchange/exchange_properties.rb +28 -28
  25. data/lib/soaspec/exchange/exchange_repeater.rb +21 -21
  26. data/lib/soaspec/exchange/request_builder.rb +108 -70
  27. data/lib/soaspec/exchange/variable_storer.rb +24 -24
  28. data/lib/soaspec/exchange_handlers/exchange_handler.rb +98 -98
  29. data/lib/soaspec/exchange_handlers/exchange_handler_defaults.rb +61 -61
  30. data/lib/soaspec/exchange_handlers/handler_accessors.rb +132 -132
  31. data/lib/soaspec/exchange_handlers/request/rest_request.rb +77 -59
  32. data/lib/soaspec/exchange_handlers/request/soap_request.rb +41 -41
  33. data/lib/soaspec/exchange_handlers/response_extractor.rb +84 -84
  34. data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +111 -111
  35. data/lib/soaspec/exchange_handlers/rest_handler.rb +307 -307
  36. data/lib/soaspec/exchange_handlers/rest_methods.rb +65 -65
  37. data/lib/soaspec/exchange_handlers/rest_parameters.rb +112 -112
  38. data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +42 -42
  39. data/lib/soaspec/exchange_handlers/soap_handler.rb +241 -241
  40. data/lib/soaspec/exe_helpers.rb +94 -94
  41. data/lib/soaspec/generate_server.rb +48 -48
  42. data/lib/soaspec/generator/.rspec.erb +5 -5
  43. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  44. data/lib/soaspec/generator/Gemfile.erb +8 -8
  45. data/lib/soaspec/generator/README.md.erb +29 -29
  46. data/lib/soaspec/generator/Rakefile.erb +20 -19
  47. data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
  48. data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
  49. data/lib/soaspec/generator/features/support/env.rb.erb +3 -3
  50. data/lib/soaspec/generator/generate_exchange.html.erb +47 -47
  51. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  52. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  53. data/lib/soaspec/generator/lib/new_rest_service.rb.erb +56 -56
  54. data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
  55. data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
  56. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  57. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  58. data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
  59. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  60. data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
  61. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  62. data/lib/soaspec/indifferent_hash.rb +9 -9
  63. data/lib/soaspec/interpreter.rb +70 -70
  64. data/lib/soaspec/matchers.rb +136 -140
  65. data/lib/soaspec/o_auth2.rb +142 -142
  66. data/lib/soaspec/soaspec_shared_examples.rb +26 -26
  67. data/lib/soaspec/spec_logger.rb +143 -143
  68. data/lib/soaspec/template_reader.rb +30 -30
  69. data/lib/soaspec/test_server/bank.wsdl +90 -90
  70. data/lib/soaspec/test_server/get_bank.rb +166 -166
  71. data/lib/soaspec/test_server/id_manager.rb +41 -41
  72. data/lib/soaspec/test_server/invoices.rb +29 -29
  73. data/lib/soaspec/test_server/namespace.xml +14 -14
  74. data/lib/soaspec/test_server/note.xml +5 -5
  75. data/lib/soaspec/test_server/puppy_service.rb +21 -21
  76. data/lib/soaspec/test_server/test_attribute.rb +14 -14
  77. data/lib/soaspec/test_server/test_namespace.rb +14 -14
  78. data/lib/soaspec/version.rb +6 -6
  79. data/lib/soaspec/virtual_server.rb +193 -190
  80. data/lib/soaspec/wait.rb +43 -43
  81. data/lib/soaspec/wsdl_generator.rb +215 -215
  82. data/soaspec.gemspec +58 -58
  83. data/test.wsdl +116 -116
  84. data/test.xml +10 -10
  85. data/test_wsdl.rb +43 -43
  86. metadata +3 -3
@@ -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
@@ -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